ecere/gui/Window: Fixed logged errors appearing
[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             List<Window> overWindows = guiApp.overWindows;
4273             Iterator<Window> it { overWindows };
4274
4275             while(it.Next())
4276             {
4277                Window w = it.data;
4278                if(trueWindow != w && !trueWindow.IsDescendantOf(w))
4279                {
4280                   it.pointer = null;
4281                   result = w.OnMouseLeave(*mods);
4282                   if(!result) break;
4283                   overWindows.TakeOut(w);
4284                }
4285             }
4286
4287             if(result && guiApp.prevWindow && trueWindow != guiApp.prevWindow)
4288             {
4289                guiApp.prevWindow.mouseInside = false;
4290                guiApp.prevWindow = null;
4291
4292                if(result)
4293                {
4294                   if(trueWindow.IsDescendantOf(prevWindow))
4295                   {
4296                      if(!overWindows.Find(prevWindow))
4297                         overWindows.Add(prevWindow);
4298                   }
4299                   // Eventually fix this not to include captured?
4300                   else if(!prevWindow.OnMouseLeave(*mods))
4301                      result = false;
4302                }
4303             }
4304             if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/)
4305             {
4306                Box box = trueWindow.box;
4307                box.left += trueWindow.absPosition.x;
4308                box.right += trueWindow.absPosition.x;
4309                box.top += trueWindow.absPosition.y;
4310                box.bottom += trueWindow.absPosition.y;
4311
4312                if(box.IsPointInside({x, y}) && trueWindow != /*guiApp.*/prevWindow /*!trueWindow.mouseInside*/)
4313                {
4314                   int overX = x - (trueWindow.absPosition.x + trueWindow.clientStart.x);
4315                   int overY = y - (trueWindow.absPosition.y + trueWindow.clientStart.y);
4316
4317                   overX = Max(Min(overX, 32767),-32768);
4318                   overY = Max(Min(overY, 32767),-32768);
4319
4320                   trueWindow.mouseInside = true;
4321                   if(!trueWindow.OnMouseOver(overX, overY, *mods))
4322                      result = false;
4323                }
4324             }
4325             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
4326             {
4327                for(w : guiApp.overWindows; w == trueWindow)
4328                {
4329                   OnMouseLeave(0);
4330                   guiApp.overWindows.TakeOut(w);
4331                   break;
4332                }
4333                guiApp.prevWindow = trueWindow;
4334             }
4335             else
4336                guiApp.prevWindow = null;
4337          }
4338          SelectMouseCursor();
4339
4340          if(window && ((!guiApp.windowMoving && !wasMoving) ||
4341             (wasMoving && guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp)) && !wasScrolling)
4342          {
4343             int clientX = x - (window.absPosition.x + window.clientStart.x);
4344             int clientY = y - (window.absPosition.y + window.clientStart.y);
4345
4346             bool (* MouseMethod)(Window instance, int x, int y, Modifiers mods);
4347
4348             clientX = Max(Min(clientX, 32767),-32768);
4349             clientY = Max(Min(clientY, 32767),-32768);
4350
4351             MouseMethod = (void *)window._vTbl[method];
4352
4353             if(MouseMethod /*&& !consequential*/ && !window.disabled)
4354             {
4355                incref window;
4356                if(!MouseMethod(window, clientX, clientY, *mods))
4357                   result = false;
4358                delete window;
4359             }
4360          }
4361          delete trueWindow;
4362          /*
4363          if(result && w && w.clickThrough && w.parent)
4364             w = w.parent;
4365          else
4366             break;
4367          */
4368          if(!result || !w || !w.clickThrough)
4369             break;
4370       }
4371       delete w;
4372       return result;
4373    }
4374
4375    // --- Mouse cursor management ---
4376
4377    bool KeyMessage(uint method, Key key, unichar character)
4378    {
4379       bool status = true;
4380       if(!parent)
4381       {
4382          if(guiApp.interimWindow)
4383             this = guiApp.interimWindow;
4384       }
4385 #ifdef _DEBUG
4386       if((SmartKey)key != alt && (SmartKey)key != Key::control && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && parent && this != parent.menuBar)
4387          Print("");
4388 #endif
4389
4390       if(!style.inactive || rootWindow != this)
4391       {
4392          bool (*KeyMethod)(Window window, Key key, unichar ch) = (void *)_vTbl[method];
4393          Window modalWindow = FindModal();
4394          Window interimMaster = master ? master.rootWindow : null;
4395
4396          incref this;
4397
4398          if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4399             status = OnSysKeyDown(key, character);
4400          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4401             status = OnSysKeyHit(key, character);
4402          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4403             status = OnSysKeyUp(key, character);
4404          if(!status)
4405          {
4406             delete this;
4407             return true;
4408          }
4409
4410          // Process Key Message for Internal UI Keyboard actions
4411          if(status && !destroyed && menuBar && state != minimized)
4412          {
4413             // Disable the ALT
4414             if((SmartKey)key != alt)
4415                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4416             if(menuBar.focus)
4417             {
4418                SmartKey sk = (SmartKey) key;
4419                if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt)
4420                {
4421                   status = menuBar.KeyMessage(method, key, character);
4422                   status = false;
4423                }
4424                else
4425                {
4426                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4427                      menuBar.OnKeyHit(escape, 0);
4428                }
4429                if(!menuBar.focus && guiApp.caretOwner)
4430                   guiApp.caretOwner.UpdateCaret(true, false);
4431             }
4432          }
4433          if(!destroyed && status)
4434          {
4435             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4436             {
4437                switch(key)
4438                {
4439                   case left: case up: case right: case down:
4440                      if(guiApp.windowMoving == this)
4441                      {
4442                         int step = 1; //8;
4443                         int w = guiApp.windowMoving.size.w;
4444                         int h = guiApp.windowMoving.size.h;
4445                         int x = guiApp.windowMoving.scrolledPos.x;
4446                         int y = guiApp.windowMoving.scrolledPos.y;
4447
4448                         if(guiApp.textMode)
4449                         {
4450                            if(key == down || key == up)
4451                               step = Max(step, textCellH);
4452                            else
4453                               step = Max(step, textCellW);
4454                         }
4455
4456                         if(guiApp.windowIsResizing)
4457                         {
4458                            switch(key)
4459                            {
4460                               case left: w-=step; break;
4461                               case right: w+=step; break;
4462                               case up: h-=step;   break;
4463                               case down: h+=step; break;
4464                            }
4465                         }
4466                         else
4467                         {
4468                            switch(key)
4469                            {
4470                               case left: x-=step; break;
4471                               case right: x+=step; break;
4472                               case up: y-=step;   break;
4473                               case down: y+=step; break;
4474                            }
4475                         }
4476
4477                         if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w;
4478                         if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h;
4479
4480                         if(!guiApp.windowIsResizing || guiApp.resizeX)
4481                            x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x;
4482                         else
4483                            x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x;
4484
4485                         if(!guiApp.windowIsResizing || guiApp.resizeY)
4486                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
4487                         else
4488                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
4489
4490                         guiApp.interfaceDriver.SetMousePosition(x, y);
4491                         ConsequentialMouseMove(true);
4492
4493                         status = false;
4494                      }
4495                      break;
4496                   case escape:
4497                   case enter:
4498                   case keyPadEnter:
4499                      if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4500                      {
4501                         guiApp.windowMoving.StopMoving();
4502                         ConsequentialMouseMove(false);
4503
4504                         status = false;
4505                      }
4506                      break;
4507                   case altSpace:
4508                      if(style.fixed)
4509                      {
4510                         ShowSysMenu(absPosition.x, absPosition.y);
4511                         status = false;
4512                      }
4513                      break;
4514                }
4515             }
4516          }
4517
4518          if(!destroyed && status && state != minimized)
4519          {
4520             // Process all the way down the children
4521             if(activeChild && !activeChild.disabled)
4522             {
4523                status = activeChild.KeyMessage(method, key, character);
4524             }
4525             if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) &&
4526                key.code != left && key.code != right && key.code != up && key.code != down)
4527             {
4528                status = activeClient.KeyMessage(method, key, character);
4529             }
4530
4531             // Default Control
4532             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4533             {
4534                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized)
4535                   // && defaultControl != activeChild)
4536                {
4537                   delete previousActive;
4538                   previousActive = activeChild;
4539                   if(previousActive) incref previousActive;
4540
4541                   ConsequentialMouseMove(false);
4542                   if((defaultControl.active ||
4543                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
4544                      defaultControl.KeyMessage(method, defaultKey, character);
4545                   status = false;
4546                }
4547             }
4548          }
4549
4550          if(!destroyed && status && (!modalWindow || this == guiApp.desktop))
4551          {
4552             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4553             {
4554                switch(key)
4555                {
4556                   case altMinus:
4557                      if(style.fixed)
4558                      {
4559                         ShowSysMenu(absPosition.x, absPosition.y);
4560                         status = false;
4561                      }
4562                      break;
4563                   //case f5:
4564                   /*
4565                   case shiftF5:
4566                      if(this != guiApp.desktop)
4567                      {
4568                         if(!guiApp.windowMoving && !guiApp.windowCaptured)
4569                         {
4570                            if(state != maximized && (key.shift ? style.sizeable : style.fixed))
4571                            {
4572                               MenuMoveOrSize(key.shift, true);
4573                               status = false;
4574                            }
4575                         }
4576                         else if(guiApp.windowMoving)
4577                         {
4578                            guiApp.windowMoving.StopMoving();
4579                            ConsequentialMouseMove(false);
4580                            status = false;
4581                         }
4582                      }
4583                      break;
4584                   */
4585                }
4586             }
4587             if(!destroyed && status && state != minimized)
4588             {
4589                if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4590                {
4591                   switch(key)
4592                   {
4593                      case tab: case shiftTab:
4594                      {
4595                         Window cycleParent = this;
4596                         if(this == guiApp.interimWindow && master && !master.style.interim && !cycleParent.style.tabCycle && master.parent)
4597                            cycleParent = master.parent;
4598
4599                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
4600                         {
4601                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
4602                            {
4603                               /*
4604                               Window child = cycleParent.activeChild;
4605
4606                               // Scroll the window to include the active control
4607                               if(cycleParent.sbh && !child.style.dontScrollHorz)
4608                               {
4609                                  if(child.scrolledPos.x < 0)
4610                                     cycleParent.sbh.Action(Position,
4611                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
4612                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
4613                                     cycleParent.sbh.Action(Position,
4614                                        cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0);
4615                               }
4616                               if(cycleParent.sbv && !child.style.dontScrollVert)
4617                               {
4618                                  if(child.scrolledPos.y < 0)
4619                                     cycleParent.sbv.Action(Position,
4620                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
4621                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
4622                                     cycleParent.sbv.Action(Position,
4623                                        cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0);
4624                               }
4625                               */
4626                               cycleParent.ConsequentialMouseMove(false);
4627                               status = false;
4628                            }
4629                         }
4630                         break;
4631                      }
4632                      case f6: case shiftF6:
4633                         if(!guiApp.windowMoving /*!guiApp.windowCaptured*/)
4634                         {
4635                            // NOT NEEDED... guiApp.windowMoving.ReleaseCapture();
4636                            if(parent == guiApp.desktop)
4637                               if(guiApp.desktop.CycleChildren(key.shift, true, false, true))
4638                               {
4639                                  status = false;
4640                                  break;
4641                               }
4642                            if(style.tabCycle)
4643                            {
4644                               delete this;
4645                               return true;
4646                            }
4647                            if(CycleChildren(key.shift, true, false, true))
4648                            {
4649                               status = false;
4650                               break;
4651                            }
4652                         }
4653                         break;
4654                      /*
4655                      // mIRC Style Window Shortcuts
4656                      case alt1: case alt2: case alt3: case alt4: case alt5:
4657                      case alt6: case alt7: case alt8: case alt9: case alt0:
4658                      {
4659                         if(numPositions)
4660                         {
4661                            Window document;
4662                            for(document = children.first; document; document = document.next)
4663                            {
4664                               if(document.style.isDocument && document.documentID - 1 == key.code - k1)
4665                               {
4666                                  if(document == activeChild)
4667                                  {
4668                                     if(document.state == minimized)
4669                                        document.SetState(normal, false, key);
4670                                     else
4671                                     {
4672                                        document.SetState(minimized, false, key);
4673                                        CycleChildren(false, true, false);
4674                                     }
4675                                  }
4676                                  else
4677                                  {
4678                                     if(activeChild.state == maximized && document.style.hasMaximize)
4679                                        document.SetState(maximized, false, key);
4680                                     else if(document.state == minimized)
4681                                        document.SetState(normal, false, key);
4682                                     document.Activate();
4683                                  }
4684                                  status = false;
4685                                  break;
4686                               }
4687                            }
4688                         }
4689                         break;
4690                      }
4691                      */
4692                   }
4693                }
4694             }
4695          }
4696
4697          if(!destroyed && status)
4698          {
4699             if(state == minimized)
4700             {
4701                delete this;
4702                return true;
4703             }
4704             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4705             {
4706                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive)
4707                {
4708                   if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character))
4709                      previousActive.ActivateEx(true, false, false, true, null, null);
4710                   delete previousActive;
4711                   status = false;
4712                }
4713             }
4714          }
4715
4716          if(!destroyed && status)
4717          {
4718             status = ProcessHotKeys(method, key, character);
4719          }
4720          if(!destroyed && status && !modalWindow && state != minimized)
4721          {
4722             if(KeyMethod)
4723                status = KeyMethod(this, key, character);
4724             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4725                status = OnKeyHit(key, character);
4726             if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
4727             {
4728                bool result = false;
4729                switch(key)
4730                {
4731                   case ctrlUp: case ctrlDown:
4732                      if(sbv && !guiApp.windowScrolling)
4733                         result = sbv.Action((key == ctrlUp) ? up : down, 0, key);
4734                      break;
4735                   case wheelUp: case wheelDown:
4736                      if(sbv && !guiApp.windowScrolling)
4737                      {
4738                         result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key);
4739                         // Do we want to do a consequential move regardless of result in this case?
4740                         ConsequentialMouseMove(false);
4741                      }
4742                      break;
4743                   case ctrlPageUp: case ctrlPageDown:
4744                      if(sbh && !guiApp.windowScrolling)
4745                         result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key);
4746                      break;
4747                }
4748                if(result)
4749                {
4750                   ConsequentialMouseMove(false);
4751                   status = false;
4752                }
4753             }
4754          }
4755          if(status && !destroyed && menuBar && state != minimized)
4756             status = menuBar.KeyMessage(method, key, character);
4757
4758          if(style.interim && /*destroyed && */status && interimMaster)
4759          {
4760             // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped...
4761             status = interimMaster.KeyMessage(method, key, character);
4762          }
4763          delete this;
4764       }
4765       return status;
4766    }
4767
4768    bool ProcessHotKeys(uint method, Key key, unichar character)
4769    {
4770       bool status = true;
4771       HotKeySlot hotKey;
4772
4773       for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next)
4774          if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) &&
4775             !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized))
4776          {
4777             Window hotKeyWindow = hotKey.window;
4778             Window parent = hotKeyWindow.parent;
4779             Window prevActiveWindow = activeChild;
4780             // For when sys buttons are placed inside the menu bar
4781             if(parent && parent._class == class(PopupMenu))
4782                parent = parent.parent;
4783
4784             // 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
4785             if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || (hotKeyWindow != parent.sysButtons[2] && hotKeyWindow != parent.sysButtons[1])))
4786                continue;
4787
4788             if(prevActiveWindow) incref prevActiveWindow;
4789             incref hotKeyWindow;
4790             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient && !hotKeyWindow.inactive)
4791                if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null))
4792                {
4793                   status = false;
4794                   delete hotKeyWindow;
4795                   delete prevActiveWindow;
4796                   break;
4797                }
4798
4799             if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4800                method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
4801             if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character))
4802             {
4803                // *********   WORKING ON THIS   ***********
4804                if(prevActiveWindow && !guiApp.interimWindow)
4805                   prevActiveWindow.ActivateEx(true, false, false, false, null, null);
4806                status = false;
4807             }
4808             else if(hotKeyWindow.style.inactive)
4809                status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character);
4810
4811             delete prevActiveWindow;
4812             delete hotKeyWindow;
4813             // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key)
4814             if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4815                status = false;
4816             break;
4817          }
4818       if(status && tabCycle)
4819       {
4820          Window child;
4821          for(child = children.first; child; child = child.next)
4822          {
4823             if(child.tabCycle && !child.ProcessHotKeys(method, key, character))
4824             {
4825                status = false;
4826                break;
4827             }
4828          }
4829       }
4830       return status;
4831    }
4832
4833
4834    // --- Windows and graphics initialization / termination ---
4835    bool SetupRoot(void)
4836    {
4837       Window child;
4838
4839       // Setup relationship with outside world (bb root || !bb)
4840       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop ||
4841          (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))
4842       {
4843          rootWindow = this;
4844          if(!tempExtents)
4845             tempExtents = new0 Extent[4];
4846          against = null;
4847       }
4848       else
4849       {
4850          /*if(guiApp.fullScreenMode)
4851             rootWindow = guiApp.desktop;
4852          else*/
4853          //rootWindow = parent.created ? parent.rootWindow : null;
4854          rootWindow = parent.rootWindow;
4855
4856          if(style.nonClient)
4857             against = &parent.box;
4858          else
4859             against = &parent.clientArea;
4860       }
4861
4862       for(child = children.first; child; child = child.next)
4863          child.SetupRoot();
4864
4865       return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false;
4866    }
4867
4868    bool Setup(bool positionChildren)
4869    {
4870       bool result = false;
4871       Window child;
4872
4873       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))))
4874       {
4875          subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
4876          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
4877
4878          if(!windowHandle)
4879             windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
4880
4881          // This was here, is it really needed?
4882          //guiApp.interfaceDriver.ActivateRootWindow(this);
4883
4884          if(!displaySystem)
4885          {
4886             displaySystem = DisplaySystem {};
4887             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
4888             {
4889                delete displaySystem;
4890             }
4891          }
4892          if(displaySystem)
4893          {
4894             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
4895             if(display.Create(displaySystem, windowHandle))
4896                result = true;
4897             else
4898             {
4899                delete display;
4900             }
4901          }
4902          // Sometimes icon does not show up on Windows XP if we set here...
4903          // guiApp.interfaceDriver.SetIcon(this, icon);
4904       }
4905       else if(this != guiApp.desktop)
4906       {
4907          display = rootWindow ? rootWindow.display : null;
4908          result = true;
4909       }
4910       else
4911          result = true;
4912
4913       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
4914          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
4915
4916       for(child = children.first; child; child = child.next)
4917       {
4918          if(child.created && !child.Setup(false))
4919             result = false;
4920
4921          if(guiApp.modeSwitching && guiApp.fullScreen && child.rootWindow == child)
4922             child.UpdateCaption();
4923       }
4924       return result;
4925    }
4926
4927    bool SetupDisplay(void)
4928    {
4929 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
4930       if(is3D) return Window3D_SetupDisplay(this); else
4931 #endif
4932       if(SetupRoot())
4933          return Setup(true);
4934       return false;
4935    }
4936
4937    class_data void ** pureVTbl;
4938
4939    bool LoadGraphics(bool creation, bool resetAnchors)
4940    {
4941       bool result = false;
4942       bool success = false;
4943       Window child;
4944       WindowState stateBackup = state;
4945
4946       if(((subclass(Window))_class).pureVTbl)
4947       {
4948          if(_vTbl == _class._vTbl)
4949          {
4950             _vTbl = ((subclass(Window))_class).pureVTbl;
4951          }
4952          else
4953          {
4954             int m;
4955             for(m = 0; m < _class.vTblSize; m++)
4956             {
4957                if(_vTbl[m] == _class._vTbl[m])
4958                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
4959             }
4960          }
4961       }
4962       if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
4963       {
4964          if(_vTbl == ((subclass(Window))_class).pureVTbl)
4965          {
4966             _vTbl = _class._vTbl;
4967          }
4968          else
4969          {
4970             int m;
4971             for(m = 0; m < _class.vTblSize; m++)
4972             {
4973                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
4974                   _vTbl[m] = _class._vTbl[m];
4975             }
4976          }
4977       }
4978
4979       if(guiApp.fullScreenMode || this != guiApp.desktop)
4980       {
4981          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
4982          if(display)
4983          {
4984             ResPtr ptr;
4985             success = true;
4986
4987             display.Lock(false);
4988             if(rootWindow == this)
4989             {
4990                // Set Color Palette
4991                display.SetPalette(palette, true);
4992
4993                // Load Cursors
4994                /*
4995                if(guiApp.fullScreenMode && this == guiApp.desktop)
4996                {
4997                   int c;
4998                   Cursor cursor;
4999
5000                   for(c=0; c<SystemCursor::enumSize; c++)
5001                      if(!guiApp.systemCursors[c].bitmap)
5002                      {
5003                         guiApp.systemCursors[c].bitmapName = guiApp.currentSkin.CursorsBitmaps(c,
5004                            &guiApp.systemCursors[c].hotSpotX,&guiApp.systemCursors[c].hotSpotY, &guiApp.systemCursors[c].paletteShades);
5005                         if(guiApp.systemCursors[c].bitmapName)
5006                         {
5007                            guiApp.systemCursors[c].bitmap = eBitmap_LoadT(guiApp.systemCursors[c].bitmapName, null,
5008                               guiApp.systemCursors[c].paletteShades ? null : guiApp.desktop.display.displaySystem);
5009                            if(guiApp.systemCursors[c].bitmap)
5010                               guiApp.systemCursors[c].bitmap.paletteShades = guiApp.systemCursors[c].paletteShades;
5011                            else
5012                               success = false;
5013                         }
5014                      }
5015                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5016                   {
5017                      cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null,
5018                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
5019                      if(cursor.bitmap)
5020                         cursor.bitmap.paletteShades = cursor.paletteShades;
5021                      else
5022                         success = false;
5023                   }
5024                   guiApp.cursorUpdate = true;
5025
5026                   display.Unlock();
5027                   ConsequentialMouseMove(false);
5028                   display.Lock(true);
5029                }
5030                */
5031             }
5032
5033             // Load Window Graphic Resources
5034
5035             /*
5036             if(usedFont == setFont || usedFont == window.systemFont)
5037                RemoveResource(usedFont);
5038             */
5039             if(setFont)
5040                RemoveResource(setFont); // TESTING setFont instead of usedFont);
5041
5042             if(systemFont)
5043                RemoveResource(systemFont);
5044
5045             if(captionFont)
5046                RemoveResource(captionFont);
5047
5048             for(ptr = resources.first; ptr; ptr = ptr.next)
5049             {
5050                if(!ptr.loaded)   // This check prevents a leak in case a watcher on 'font' calls AddResource (ListBox FontResource leak)
5051                   ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
5052             }
5053             if(setFont)
5054                AddResource(setFont);
5055             if(systemFont)
5056                AddResource(systemFont);
5057
5058             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
5059
5060             firewatchers font;
5061
5062             /*
5063             if(!setFont)
5064             {
5065                //if(master && master.font)
5066                if(parent && parent.font)
5067                {
5068                   font = FontResource
5069                   {
5070                      faceName = parent.font.faceName,
5071                      size = parent.font.size,
5072                      bold = parent.font.bold,
5073                      italic = parent.font.italic,
5074                      underline = parent.font.underline
5075                   };
5076                   //font = parent.font;
5077                   watch(parent) { font { } };
5078                }
5079                else
5080                   font = guiApp.currentSkin.SystemFont();
5081                AddResource(font);
5082
5083                firewatchers font;
5084             }
5085             */
5086
5087             captionFont = guiApp.currentSkin ? guiApp.currentSkin.CaptionFont() : null;
5088             AddResource(captionFont);
5089
5090             if(OnLoadGraphics())
5091             {
5092                int x,y,w,h;
5093
5094                display.Unlock();
5095
5096                //SetScrollLineStep(sbStep.x, sbStep.y);
5097
5098                if(this != guiApp.desktop)
5099                {
5100                   if(resetAnchors)
5101                   {
5102                      normalAnchor = anchor;
5103                      normalSizeAnchor = sizeAnchor;
5104                   }
5105
5106                   // Break the anchors for moveable/resizable windows
5107                   /*
5108                   if(style.fixed && style.isDocument)
5109                   {
5110                      ComputeAnchors(ax, ay, aw, ah, &x, &y, &w, &h);
5111                      ax = x;
5112                      ay = y;
5113                      aw = w;
5114                      ah = h;
5115                      anchored = false;
5116                   }
5117                   */
5118                   switch(state)
5119                   {
5120                      case maximized:
5121
5122                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5123                         stateSizeAnchor = SizeAnchor {};
5124                         break;
5125
5126                      case minimized:
5127                      {
5128                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5129
5130                         stateAnchor =
5131                            Anchor
5132                            {
5133                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
5134                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
5135                            };
5136
5137                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5138                         break;
5139                      }
5140                      case normal:
5141                         stateAnchor = normalAnchor;
5142                         stateSizeAnchor = normalSizeAnchor;
5143                         break;
5144                   }
5145                   position = Point { };
5146                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5147
5148                }
5149                else
5150                {
5151                   x = scrolledPos.x;
5152                   y = scrolledPos.y;
5153                   w = size.w;
5154                   h = size.h;
5155                }
5156
5157                if(Position(x, y, w, h, true, false, true, true, true, true))
5158                {
5159                   if((this != guiApp.desktop || guiApp.fullScreenMode) && rootWindow == this)
5160                   {
5161                      if(!style.hidden)
5162                         guiApp.interfaceDriver.SetRootWindowState(this, normal, true);
5163                   }
5164
5165                   Update(null);
5166
5167                   result = true;
5168                }
5169             }
5170             else
5171             {
5172                result = false;
5173                display.Unlock();
5174             }
5175          }
5176       }
5177       else
5178       {
5179          success = result = true;
5180       }
5181
5182       if(!creation && result)
5183       {
5184          // Load menu bar first because sys buttons are on it...
5185          if(menuBar)
5186          {
5187             if(!menuBar.LoadGraphics(false, resetAnchors))
5188             {
5189                result = false;
5190                success = false;
5191             }
5192          }
5193          for(child = children.first; child; child = child.next)
5194          {
5195             if(child.created && child != menuBar && !child.LoadGraphics(false, resetAnchors))
5196             {
5197                result = false;
5198                success = false;
5199             }
5200          }
5201          if(!creation)
5202             CreateSystemChildren();
5203
5204          OnApplyGraphics();
5205       }
5206       if(this == guiApp.desktop && !guiApp.fullScreenMode)
5207       {
5208          if(activeChild)
5209             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
5210       }
5211       if(!success)
5212          LogErrorCode(graphicsLoadingFailed, _class.name);
5213
5214       // Do this here to avoid problems on Windows
5215       if(rootWindow == this && parent && stateBackup == maximized)
5216          property::state = maximized;
5217       return result;
5218    }
5219
5220    void UnloadGraphics(bool destroyWindows)
5221    {
5222       Window child;
5223
5224       // Free children's graphics
5225       for(child = children.first; child; child = child.next)
5226          child.UnloadGraphics(destroyWindows);
5227
5228       if(display)
5229          display.Lock(false);
5230
5231       // Free cursors
5232       if(guiApp.fullScreenMode && this == guiApp.desktop)
5233       {
5234          Cursor cursor;
5235          SystemCursor c;
5236
5237          for(c=0; c<SystemCursor::enumSize; c++)
5238             if(guiApp.systemCursors[c].bitmap)
5239                delete guiApp.systemCursors[c].bitmap;
5240
5241          for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5242             delete cursor.bitmap;
5243
5244          guiApp.cursorBackground.Free();
5245       }
5246
5247       if(display && display.displaySystem)
5248       {
5249          ResPtr ptr;
5250
5251          for(ptr = resources.first; ptr; ptr = ptr.next)
5252          {
5253             if(ptr.loaded)
5254             {
5255                display.displaySystem.UnloadResource(ptr.resource, ptr.loaded);
5256                ptr.loaded = null;
5257             }
5258          }
5259
5260          // Free window graphics
5261          OnUnloadGraphics();
5262
5263          // Free skin graphics
5264          if(rootWindow == this)
5265          {
5266             DisplaySystem displaySystem = display.displaySystem;
5267             if(is3D)
5268             {
5269                display.driverData = null;
5270                display.displaySystem = null;
5271             }
5272             display.Unlock();
5273             delete display;
5274             if(displaySystem && !displaySystem.numDisplays && !is3D)
5275                delete displaySystem;
5276          }
5277          else
5278          {
5279             display.Unlock();
5280             display = null;
5281          }
5282       }
5283
5284       if(guiApp.acquiredWindow && this == guiApp.acquiredWindow.rootWindow)
5285          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, false);
5286
5287       if(this == guiApp.desktop || parent == guiApp.desktop)
5288       {
5289          if((guiApp.fullScreenMode || this != guiApp.desktop) && rootWindow == this && windowHandle && destroyWindows)
5290             guiApp.interfaceDriver.DestroyRootWindow(this);
5291       }
5292    }
5293
5294    // --- Window Hiding ---
5295
5296    void SetVisibility(bool state)
5297    {
5298       bool visible = (style.hidden || !created) ? false : state;
5299       if(visible != this.visible)
5300       {
5301          Window child;
5302
5303          this.visible = visible;
5304          for(child = children.first; child; child = child.next)
5305             child.SetVisibility(visible);
5306          Update(null);
5307          ConsequentialMouseMove(false);
5308          if(parent && !nonClient) parent.OnChildVisibilityToggled(this, visible);
5309       }
5310    }
5311
5312    // --- Windows and graphics initialization / termination ---
5313
5314    bool DisplayModeChanged(void)
5315    {
5316       bool result = false;
5317       if(!guiApp.fullScreenMode && !guiApp.modeSwitching/* && guiApp.desktop.active*/)
5318       {
5319          guiApp.modeSwitching = true;
5320          UnloadGraphics(false);
5321          if(SetupDisplay())
5322             if(LoadGraphics(false, false))
5323                result = true;
5324          guiApp.modeSwitching = false;
5325       }
5326       return result;
5327    }
5328
5329    // --- Window updates system ---
5330
5331    void UpdateDirty(Box updateBox)
5332    {
5333       if(!manageDisplay) { OnRedraw(null);return; }
5334       if(visible)
5335       {
5336          if(display && (!guiApp.fullScreenMode || guiApp.desktop.active) && !guiApp.modeSwitching)
5337          {
5338             display.Lock(true);
5339             if(display.flags.flipping)
5340             {
5341                Update(null);
5342                rootWindow.UpdateDisplay();
5343             }
5344             else
5345                UpdateBackDisplay(updateBox);
5346
5347             if(guiApp.fullScreenMode)
5348             {
5349                guiApp.cursorUpdate = true;
5350                guiApp.PreserveAndDrawCursor();
5351             }
5352             if(guiApp.fullScreenMode)
5353                guiApp.RestoreCursorBackground();
5354             display.Unlock();
5355          }
5356       }
5357    }
5358
5359    // This function is strictly called as a result of system window activation
5360    bool ExternalActivate(bool active, bool activateRoot, Window window, Window swap)
5361    {
5362       bool result = true;
5363       Window interimMaster = null;
5364       Window interimWindow = guiApp.interimWindow;
5365       if(interimWindow && interimWindow.master)
5366          interimMaster = interimWindow.master.rootWindow;
5367
5368       if(active && state == minimized && window.parent) // && (!window.nativeDecorations || window.rootWindow != window)
5369          // SetState(normal, false, 0);
5370          SetState(lastState, false, 0);
5371
5372       if(interimMaster && swap == interimMaster && interimMaster.IsSlaveOf(window))
5373          return false;
5374
5375       incref this;
5376       /* WTH is this doing here?
5377       while(swap && swap.activeChild)
5378       {
5379          swap = swap.activeChild;
5380       }
5381       */
5382       // TESTING THIS BEFORE...
5383       if(interimWindow && this == interimMaster)
5384       {
5385          if(active)
5386          {
5387             // Window interimSwap = this;
5388             Window menuBar = this.menuBar;
5389             if(menuBar && interimWindow.master == menuBar)
5390             {
5391                /*
5392                while(interimSwap && interimSwap.activeChild)
5393                   interimSwap = interimSwap.activeChild;
5394
5395                result = interimWindow.ActivateEx(false, false, false, activateRoot, null,
5396                (menuBar && interimWindow.master == menuBar) ? menuBar : interimSwap);
5397                */
5398                result = /*interimWindow.*/ActivateEx(false, false, false, activateRoot, null, menuBar);
5399                //result = ActivateEx(true, true, false, activateRoot, window, null);
5400             }
5401          }
5402       }
5403       else
5404          // Testing & FindModal() here: broke reactivating when a modal dialog is up (didn't root activate dialog)
5405          result = ActivateEx(active, active, false, activateRoot /*&& FindModal()*/, window, swap);
5406
5407       if(interimWindow == this && interimMaster && !active)
5408       {
5409          while(interimMaster && interimMaster.interim && interimMaster.master)
5410          {
5411             // printf("Going up one master %s\n", interimMaster._class.name);
5412             interimMaster = interimMaster.master.rootWindow;
5413          }
5414          // printf("Unactivating interim master %s (%x)\n", interimMaster._class.name, interimMaster);
5415          interimMaster.ActivateEx(active, active, false, activateRoot, window, swap);
5416       }
5417       delete this;
5418       return result;
5419    }
5420
5421    bool DestroyEx(int64 returnCode)
5422    {
5423       OldLink slave;
5424       Timer timer, nextTimer;
5425       Window child;
5426       OldLink prevOrder = null;
5427       Window client = null;
5428
5429       if(parent) stopwatching(parent, font);
5430
5431       // if(window.modalSlave) return false;
5432       if(destroyed || !created)
5433       {
5434          if(master)
5435          {
5436             /*
5437             if(destroyed)
5438             {
5439                OldLink slave = master.slaves.FindLink(this);
5440                master.slaves.Delete(slave);
5441             }
5442             */
5443             // TOFIX IMMEDIATELY: COMMENTED THIS OUT... causes problem second time creating file dialog
5444             //master = null;
5445          }
5446          return true;
5447       }
5448
5449       this.returnCode = (DialogResult)returnCode;
5450
5451       AcquireInput(false);
5452
5453       destroyed = true;
5454       if(hotKey)
5455       {
5456          master.hotKeys.Delete(hotKey);
5457          hotKey = null;
5458       }
5459
5460       if(guiApp.prevWindow == this)
5461       {
5462          guiApp.prevWindow = null;
5463          OnMouseLeave(0);
5464       }
5465       else
5466       {
5467          for(w : guiApp.overWindows; w == this)
5468          {
5469             OnMouseLeave(0);
5470             guiApp.overWindows.TakeOut(w);
5471             break;
5472          }
5473       }
5474       if(guiApp.caretOwner == this)
5475       {
5476          guiApp.interfaceDriver.SetCaret(0,0,0);
5477          UpdateCaret(false, true);
5478          guiApp.caretEnabled = false;
5479       }
5480
5481       /*
5482       if(cycle)
5483          parent.childrenCycle.Remove(cycle);
5484       */
5485       if(order)
5486       {
5487          OldLink tmpPrev = order.prev;
5488          if(tmpPrev && !(((Window)tmpPrev.data).style.hidden) && !(((Window)tmpPrev.data).destroyed) && (((Window)tmpPrev.data).created))
5489             prevOrder = tmpPrev;
5490          for(;;)
5491          {
5492             client = tmpPrev ? tmpPrev.data : null;
5493             if(client == this) { client = null; break; }
5494             if(client && (client.style.hidden || client.destroyed || !client.created))
5495                tmpPrev = client.order.prev;
5496             else
5497             {
5498                if(client)
5499                   prevOrder = tmpPrev;
5500                break;
5501             }
5502          }
5503
5504          // If this window can be an active client, make sure the next window we activate can also be one
5505          if(!style.nonClient && style.isActiveClient)
5506          {
5507             tmpPrev = prevOrder;
5508             for(;;)
5509             {
5510                client = tmpPrev ? tmpPrev.data : null;
5511                if(client == this) { client = null; break; }
5512                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
5513                   tmpPrev = client.order.prev;
5514                else
5515                {
5516                   if(client)
5517                      prevOrder = tmpPrev;
5518                   break;
5519                }
5520             }
5521             if(client && client.style.hidden) client = null;
5522          }
5523          // parent.childrenOrder.Remove(order);
5524       }
5525
5526       if(parent && style.isActiveClient && visible)
5527       {
5528          if(state == minimized) parent.numIcons--;
5529          parent.numPositions--;
5530       }
5531
5532       // TESTING THIS HERE!
5533       created = false;
5534       visible = false;
5535
5536       // If no display, don't bother deactivating stuff (causes unneeded problems when trying
5537       // to create a window inside a rootwindow that's being destroyed)
5538       // DISABLED THIS BECAUSE OF CREATING WINDOW IN DESKTOP IN WINDOWED MODE
5539
5540       if(master && !master.destroyed /*&&
5541          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5542       {
5543          if(master.defaultControl == this)
5544             master.defaultControl = null;
5545       }
5546       if(parent)
5547          parent.OnChildAddedOrRemoved(this, true);
5548       if(parent && !parent.destroyed /*&&
5549          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5550       {
5551          if((parent.activeChild == this /*|| parent.activeClient == this */|| guiApp.interimWindow == this))
5552          {
5553             if(order && prevOrder && prevOrder.data != this && active)
5554             {
5555                //((Window)prevOrder.data).ActivateEx(true, false, false, false /*true*/, null);
5556
5557                ((Window)prevOrder.data).ActivateEx(true, false, false, (rootWindow == this) ? true : false, null, null);
5558                if(parent.activeClient == this)
5559                {
5560                   parent.activeClient = null;
5561                   parent.UpdateActiveDocument(null);
5562                }
5563             }
5564             else
5565             {
5566                if(guiApp.interimWindow == this)
5567                {
5568                   bool goOn = true;
5569                   PropagateActive(false, null, &goOn, true);
5570                }
5571                else
5572                {
5573                   //if(window.parent.activeChild == window)
5574                      parent.activeChild = null;
5575                   if(!style.nonClient /*&& style.isActiveClient*/)
5576                   {
5577                      Window previous = parent.activeClient;
5578                      if(style.isActiveClient)
5579                         parent.activeClient = null;
5580                      parent.UpdateActiveDocument(previous);
5581                   }
5582                }
5583             }
5584          }
5585          else if(parent.activeClient == this)
5586          {
5587             parent.activeClient = client;
5588             parent.UpdateActiveDocument(this);
5589
5590          }
5591       }
5592       if(guiApp.interimWindow == this)
5593       {
5594          guiApp.interimWindow = null;
5595          if(guiApp.caretOwner)
5596          {
5597             Window desktop = guiApp.desktop;
5598             if(desktop.activeChild && desktop.activeChild.menuBar && !desktop.activeChild.menuBar.focus)
5599                guiApp.caretOwner.UpdateCaret(false, false);
5600          }
5601       }
5602
5603       active = false;
5604       if(_isModal && master && master.modalSlave == this)
5605          master.modalSlave = null;
5606
5607       if(parent)
5608       {
5609          if(!guiApp.caretOwner && parent.caretSize)
5610          {
5611             guiApp.caretOwner = parent;
5612             parent.UpdateCaret(false, false);
5613             parent.Update(null);
5614          }
5615
5616          // Why was this commented out?
5617          GetRidOfVirtualArea();
5618       }
5619       /*
5620       delete cycle;
5621       delete order;
5622       */
5623       dirtyArea.Free(null);
5624       dirtyBack.Free(null);
5625       scrollExtent.Free(null);
5626
5627       /* ATTEMPTING TO MOVE THAT ABOVE
5628       created = false;
5629       visible = false;
5630       */
5631
5632       /*
5633       OnDestroy();
5634       {
5635          //Window next;
5636          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5637          for(;(child = window.children.first);)
5638          {
5639             for(; child && (child.destroyed || !child.created); child = child.next);
5640             if(child)
5641                child.DestroyEx(0);
5642             else
5643                break;
5644          }
5645       }
5646       */
5647
5648       UnloadGraphics(true);
5649
5650       if(previousActive)
5651          delete previousActive;
5652
5653       menuBar = null;
5654       // statusBar = null;
5655       sbv = sbh = null;
5656
5657       if(master && !master.destroyed)
5658       {
5659          //master.NotifyDestroyed(this, this.returnCode);
5660          NotifyDestroyed(master, this, this.returnCode);
5661       }
5662
5663       for(timer = guiApp.windowTimers.first; timer; timer = nextTimer)
5664       {
5665          nextTimer = timer.next;
5666          if(timer.window == this)
5667          {
5668             // WHY WERE WE SETTING THIS TO NULL? NO MORE WINDOW WHEN RECREATING...
5669             // timer.window = null;
5670             timer.Stop();
5671             //delete timer;
5672          }
5673       }
5674
5675       if(this == guiApp.windowMoving)
5676          StopMoving();
5677
5678       if(guiApp.windowCaptured == this)
5679          ReleaseCapture();
5680          //guiApp.windowCaptured = null;
5681
5682       if(rootWindow != this && rootWindow)
5683          rootWindow.ConsequentialMouseMove(false);
5684
5685       rootWindow = null;
5686
5687       OnDestroy();
5688
5689       {
5690          //Window next;
5691          //for(child = children.first; next = child ? child.next : null, child; child = next)
5692          for(;(child = children.first); )
5693          {
5694             for(; child && (child.destroyed || !child.created); child = child.next);
5695             if(child)
5696                child.DestroyEx(0);
5697             else
5698                break;
5699          }
5700       }
5701
5702       // master = null;
5703
5704       /* // MOVED THIS UP...
5705       {
5706          //Window next;
5707          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5708          for(;(child = window.children.first); )
5709          {
5710             for(; child && (child.destroyed || !child.created); child = child.next);
5711             if(child)
5712                child.DestroyEx(0);
5713             else
5714                break;
5715          }
5716       }
5717       */
5718
5719       while((slave = slaves.first))
5720       {
5721          for(; slave && (((Window)slave.data).destroyed || !((Window)slave.data).created); slave = slave.next);
5722          if(slave)
5723             ((Window)slave.data).DestroyEx(0);
5724          else
5725             break;
5726       }
5727
5728       if(guiApp.caretOwner == this)
5729          guiApp.caretOwner = null;
5730
5731       sysButtons[0] = null;
5732       sysButtons[1] = null;
5733       sysButtons[2] = null;
5734       activeChild = null;
5735
5736       if(rootWindow != this)
5737       {
5738          Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
5739          if(style.nonClient)
5740          {
5741             box.left   -= parent.clientStart.x;
5742             box.top    -= parent.clientStart.y;
5743             box.right  -= parent.clientStart.x;
5744             box.bottom -= parent.clientStart.y;
5745          }
5746          if(parent) parent.Update(box);
5747       }
5748       /*
5749       if(master)
5750       {
5751          OldLink slave = master.slaves.FindVoid(this);
5752          master.slaves.Delete(slave);
5753          master = null;
5754       }
5755
5756       if(parent)
5757       {
5758          parent.children.Remove(this);
5759          parent = null;
5760       }
5761       */
5762
5763       //autoCreate = false;
5764       //created = false;
5765
5766       // SHOULD THIS BE HERE? FIXED CRASH WITH GOTO DIALOG
5767       if(((subclass(Window))_class).pureVTbl)
5768       {
5769          if(_vTbl == _class._vTbl)
5770          {
5771             _vTbl = ((subclass(Window))_class).pureVTbl;
5772          }
5773          else
5774          {
5775             int m;
5776             for(m = 0; m < _class.vTblSize; m++)
5777             {
5778                if(_vTbl[m] == _class._vTbl[m])
5779                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5780             }
5781          }
5782       }
5783
5784       delete this;
5785       return true;
5786    }
5787
5788    void SetStateEx(WindowState newState, bool activate)
5789    {
5790       int x,y,w,h;
5791       WindowState prevState = state;
5792
5793       state = newState;
5794
5795       if(prevState != newState)
5796          lastState = prevState;
5797
5798       if(rootWindow != this || !nativeDecorations || !windowHandle)
5799       {
5800          if(style.isActiveClient && !style.hidden && prevState == minimized)
5801             parent.numIcons--;
5802
5803          // This block used to be at the end of the function... moved it for flicker problem in X
5804          // ------------------------------------------------------
5805          switch(state)
5806          {
5807             case normal:
5808                stateAnchor = normalAnchor;
5809                stateSizeAnchor = normalSizeAnchor;
5810                break;
5811             case maximized:
5812                stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5813                stateSizeAnchor = SizeAnchor {};
5814                break;
5815             case minimized:
5816             {
5817                int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5818                Window child;
5819                int size = 256;
5820                byte * idBuffer = new0 byte[size];
5821                int c;
5822                for(child = parent.children.first; child; child = child.next)
5823                {
5824                   if(child != this && child.state == minimized)
5825                   {
5826                      if(child.iconID > size - 2)
5827                      {
5828                         idBuffer = renew0 idBuffer byte[size*2];
5829                         memset(idBuffer + size, 0, size);
5830                         size *= 2;
5831                      }
5832                      idBuffer[child.iconID] = (byte)bool::true;
5833                   }
5834                }
5835                for(c = 0; c<size; c++)
5836                   if(!idBuffer[c])
5837                      break;
5838                iconID = c;
5839                delete idBuffer;
5840                if(style.isActiveClient && !style.hidden)
5841                   parent.numIcons++;
5842
5843                stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
5844                stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5845                break;
5846             }
5847          }
5848          // TOCHECK: Why was this here?
5849          //position.x = (tx > 0) ? tx & 0xFFFFF : tx;
5850          //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
5851          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5852
5853          Position(x, y, w, h, true, true, true, true, false, true);
5854
5855          if(!style.inactive && !style.interim && parent && this == parent.activeClient)
5856             parent.UpdateActiveDocument(null);
5857       }
5858
5859       CreateSystemChildren();
5860       // ------------------------------------------------------
5861    }
5862
5863    int GetPositionID(Window forChild)
5864    {
5865       Window child;
5866       int size = 256;
5867       byte * idBuffer = new0 byte[size];
5868       int c;
5869
5870       for(child = children.first; child; child = child.next)
5871       {
5872          if(child.style.isActiveClient && !child.style.hidden && child != forChild)
5873          {
5874             if(child.positionID > size - 2)
5875             {
5876                idBuffer = renew0 idBuffer byte[size*2];
5877                memset(idBuffer + size, 0, size);
5878                size *= 2;
5879             }
5880             idBuffer[child.positionID] = (byte)bool::true;
5881          }
5882       }
5883       for(c = 0; c<size; c++)
5884          if(!idBuffer[c])
5885             break;
5886       delete idBuffer;
5887       return c;
5888    }
5889
5890    // --- Window related graphics ---
5891
5892    void SetPalette(ColorAlpha * newPalette, bool colorMatch)
5893    {
5894       palette = newPalette;
5895       if(rootWindow.display)
5896          rootWindow.display.SetPalette(palette, colorMatch);
5897    }
5898
5899    public bool AcquireInput(bool acquired)
5900    {
5901       bool result = true;
5902       if(acquiredInput != acquired)
5903       {
5904          if(active || (!visible && creationActivation == activate))
5905             result = AcquireInputEx(acquired);
5906          /*if(!result)
5907          {
5908             Print("");
5909          }*/
5910          acquiredInput = acquired ? result : !result;
5911       }
5912       return result;
5913    }
5914
5915    void ListChildren(ListBox listBox)
5916    {
5917       Window child;
5918       char caption[2048];
5919       for(child = children.first; child; child = child.next)
5920       {
5921          if(child.cycle && !child.style.nonClient && child.style.isActiveClient && child.visible)
5922          {
5923             DataRow row = listBox.AddRow();
5924             row.tag = (int64)(intptr)child;
5925             child.FigureCaption(caption);
5926             row.SetData(null, caption);
5927          }
5928       }
5929    }
5930
5931    void UpdateVisual(Box extent)
5932    {
5933       if(guiApp.driver != null)
5934       {
5935          if(guiApp.fullScreenMode && guiApp.desktop.display)
5936          {
5937             guiApp.desktop.mutex.Wait();
5938             guiApp.desktop.display.Lock(true);
5939
5940             Update(extent);
5941             if(guiApp.desktop.active)
5942             {
5943                if(guiApp.desktop.dirty || guiApp.cursorUpdate)
5944                {
5945                   if(guiApp.desktop.display.flags.flipping)
5946                      guiApp.desktop.Update(null);
5947                   guiApp.desktop.UpdateDisplay();
5948                   guiApp.cursorUpdate = true;
5949                }
5950                if(guiApp.cursorUpdate || guiApp.desktop.dirty)
5951                {
5952                   guiApp.PreserveAndDrawCursor();
5953                   // guiApp.desktop.display.ShowScreen();
5954                   guiApp.cursorUpdate = false;
5955                   guiApp.desktop.dirty = false;
5956                   guiApp.RestoreCursorBackground();
5957                }
5958             }
5959
5960             guiApp.desktop.display.Unlock();
5961             guiApp.desktop.mutex.Release();
5962          }
5963          else
5964          {
5965             Window rootWindow = this.rootWindow;
5966             rootWindow.mutex.Wait();
5967             display.Lock(true);
5968
5969             Update(extent);
5970             if(guiApp.waiting)
5971                guiApp.SignalEvent();
5972             else
5973             {
5974                guiApp.waitMutex.Wait();
5975                guiApp.interfaceDriver.Lock(rootWindow);
5976                if(!rootWindow.style.hidden && rootWindow.dirty)
5977                {
5978                   if(rootWindow.display)
5979                   {
5980                      rootWindow.UpdateDisplay();
5981                      //rootWindow.display.ShowScreen(null);
5982                   }
5983                   rootWindow.dirty = false;
5984                }
5985                guiApp.interfaceDriver.Unlock(rootWindow);
5986                guiApp.waitMutex.Release();
5987             }
5988             display.Unlock();
5989             rootWindow.mutex.Release();
5990          }
5991       }
5992    }
5993
5994    void UnlockDisplay(void)
5995    {
5996       guiApp.interfaceDriver.Unlock(rootWindow);
5997    }
5998
5999    void LockDisplay(void)
6000    {
6001       guiApp.interfaceDriver.Lock(rootWindow);
6002    }
6003
6004    Surface GetSurface(Box box)
6005    {
6006       return Redraw((box == null) ? this.box : box);
6007    }
6008
6009    void SetMousePosition(int x, int y)
6010    {
6011       guiApp.interfaceDriver.SetMousePosition(x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y);
6012    }
6013
6014    /*
6015    void IntegrationActivate(bool active)
6016    {
6017       if(!guiApp.modeSwitching && !guiApp.fullScreenMode)
6018       {
6019          isForegroundWindow = true;
6020          ActivateEx(active, active, false, false, null, null);
6021          isForegroundWindow = false;
6022       }
6023    }
6024    */
6025
6026    Window QueryCapture(void)
6027    {
6028       return guiApp.windowCaptured;
6029    }
6030
6031    int GetDocumentID(void)
6032    {
6033       Window child;
6034       int size = 256;
6035       byte * idBuffer = new0 byte[size];
6036       int c;
6037
6038       for(child = children.first; child; child = child.next)
6039       {
6040          // TO CHECK: Do we want a documentID when we already have a file name?
6041          if(child.style.isDocument && !child.fileName)
6042          {
6043             if(child.documentID-1 > size - 2)
6044             {
6045                idBuffer = renew0 idBuffer byte[size*2];
6046                memset(idBuffer + size, 0, size);
6047                size *= 2;
6048             }
6049             idBuffer[child.documentID-1] = 1;
6050          }
6051       }
6052       for(c = 0; c<size; c++)
6053          if(!idBuffer[c])
6054             break;
6055       numDocuments++;
6056       delete idBuffer;
6057       return c + 1;
6058    }
6059
6060    void SetInitSize(Size size)
6061    {
6062       int x, y, w, h;
6063       sizeAnchor.size = size;
6064       normalSizeAnchor = sizeAnchor;
6065
6066       // Break the anchors for moveable/resizable windows
6067       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6068       {
6069          stateAnchor = normalAnchor;
6070          stateSizeAnchor = normalSizeAnchor;
6071
6072          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6073          Position(x,y, w, h, true, true, true, true, false, true);
6074       }
6075    }
6076
6077    void MenuMoveOrSize(bool resize, bool setCursorPosition)
6078    {
6079       if(this != guiApp.desktop && state != maximized && (resize ? (state != minimized && style.sizable) : (style.fixed || moveable)))
6080       {
6081          guiApp.windowIsResizing = resize;
6082          guiApp.windowMoving = this;
6083          guiApp.windowMovingStart = guiApp.movingLast = absPosition;
6084          if(guiApp.windowIsResizing)
6085          {
6086             guiApp.windowMovingStart.x += size.w - 1;
6087             guiApp.windowMovingStart.y += size.h - 1;
6088          }
6089          guiApp.windowMovingBefore = scrolledPos;
6090          guiApp.windowResizingBefore = size;
6091          guiApp.windowMoving.UpdateDecorations();
6092          if(guiApp.windowIsResizing)
6093             guiApp.resizeEndX = guiApp.resizeEndY = true;
6094
6095          if(setCursorPosition)
6096             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
6097          else
6098          {
6099             int x, y;
6100             guiApp.interfaceDriver.GetMousePosition(&x, &y);
6101             guiApp.windowMovingStart.x += x - absPosition.x;
6102             guiApp.windowMovingStart.y += y - absPosition.y;
6103          }
6104
6105          if(guiApp.windowMoving)
6106          {
6107             if(guiApp.windowMoving.style.nonClient)
6108                guiApp.windowMoving.parent.SetMouseRangeToWindow();
6109             else
6110                guiApp.windowMoving.parent.SetMouseRangeToClient();
6111          }
6112
6113          Capture();
6114
6115          if(this == rootWindow)
6116             guiApp.interfaceDriver.StartMoving(rootWindow, guiApp.windowMovingStart.x, guiApp.windowMovingStart.y, true);
6117       }
6118    }
6119
6120    void SetupFileMonitor()
6121    {
6122       if(!fileMonitor)
6123       {
6124          fileMonitor = FileMonitor
6125          {
6126             this, FileChange { modified = true };
6127
6128             bool OnFileNotify(FileChange action, const char * param)
6129             {
6130                incref this;
6131                fileMonitor.StopMonitoring();
6132                if(OnFileModified(action, param))
6133                   fileMonitor.StartMonitoring();
6134                delete this;
6135                return true;
6136             }
6137          };
6138          incref fileMonitor;
6139       }
6140    }
6141
6142 public:
6143    // normal Methods
6144    bool Create()
6145    {
6146       bool result = false;
6147
6148       if(created)
6149          result = true;
6150       else if(guiApp && guiApp.driver != null)
6151       {
6152          OldLink slaveHolder;
6153          Window last;
6154          bool visible = !style.hidden;
6155
6156          if(style.embedded)
6157          {
6158             systemParent = parent;
6159             parent = guiApp.desktop;
6160          }
6161          last = parent ? parent.children.last : null;
6162
6163          if((parent && parent != guiApp.desktop && !parent.created) ||
6164             (master && master != guiApp.desktop && !master.created))
6165             return false;
6166
6167          if(parent)
6168             stopwatching(parent, font);
6169
6170          if(!parent)
6171             property::parent = guiApp.desktop;
6172          if(!master) master = parent;
6173
6174          if(_isModal && master.modalSlave)
6175             property::master = master.modalSlave;
6176             //return false;
6177
6178          if(parent)
6179             parent.children.Remove(this);
6180          if(master)
6181          {
6182             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
6183                if(slaveHolder.data == this)
6184                {
6185                   master.slaves.Delete(slaveHolder);
6186                   break;
6187                }
6188          }
6189
6190          if(parent == guiApp.desktop && !mutex)
6191             mutex = Mutex {};
6192
6193          if(style.isDocument)
6194          {
6195             if(parent)
6196                parent.numDocuments--;
6197             documentID = parent.GetDocumentID();
6198          }
6199
6200          if(!style.stayOnTop)
6201             for(; last && last.style.stayOnTop; last = last.prev);
6202
6203          parent.children.Insert((last == this) ? null : last, this);
6204          //parent.children.Add(this);
6205
6206          if(!dispDriver)
6207             dispDriver = parent.dispDriver;
6208          destroyed = false;
6209          if(_isModal)
6210             master.modalSlave = this;
6211
6212          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
6213
6214          incref this;
6215          incref this;
6216
6217          master.slaves.Add(slaveHolder = OldLink { data = this });
6218          if(slaveHolder)
6219          {
6220             if(setHotKey)
6221             {
6222                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
6223             }
6224             if(style.isDefault && !master.defaultControl)
6225                master.defaultControl = this;
6226
6227             stateAnchor = normalAnchor = anchor;
6228             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
6229
6230             // TOCHECK: Why is this here?
6231             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
6232             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
6233
6234             this.visible = false;
6235             style.hidden = true;
6236
6237             //created = true;
6238             // autoCreate = true;
6239             wasCreated = true;
6240             if(SetupDisplay())
6241             {
6242                created = true;
6243                if(OnCreate())
6244                {
6245                   /*
6246                   if(parent == guiApp.desktop)
6247                      Log("LoadGraphics %s\n", caption);
6248                   */
6249                   if(LoadGraphics(true, false))
6250                   {
6251                      if(!setFont)
6252                      {
6253                         watch(parent)
6254                         {
6255                            font
6256                            {
6257                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
6258                               firewatchers font;
6259                               Update(null);
6260                            }
6261                         };
6262                      }
6263
6264                      if(style.hasMenuBar /*&& menu*/)
6265                      {
6266                         menuBar =
6267                            PopupMenu
6268                            {
6269                               this,
6270                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
6271                               interim = false, inactive = true, nonClient = true, size.h = 24
6272                            };
6273                         menuBar.Create();
6274                      }
6275
6276                      if(statusBar)
6277                         statusBar.Create();
6278
6279                      // Create the system buttons
6280                      CreateSystemChildren();
6281
6282                      UpdateActiveDocument(null);
6283
6284                      if(style.isDocument)
6285                      {
6286                         if(menu)
6287                         {
6288                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6289                            if(item) item.disabled = !modifiedDocument && fileName;
6290                         }
6291                      }
6292
6293                      /*
6294                      if(parent == guiApp.desktop)
6295                         Log("Preemptive SetState %s\n", caption);
6296                      */
6297
6298                      // Preemptive Set State to ensure proper anchoring
6299                      SetStateEx(state, false);
6300                      /*
6301                      style.hidden = true;
6302                      visible = false;
6303                      */
6304
6305                      {
6306                         Window child, next;
6307                         for(child = children.first; child; child = next)
6308                         {
6309                            next = child.next;
6310                            if(!child.created && (child.autoCreate || child.wasCreated))
6311                               child.Create();
6312                         }
6313                      }
6314
6315                      {
6316                         OldLink link, next;
6317                         for(link = slaves.first; link; link = next)
6318                         {
6319                            Window slave = link.data;
6320                            next = link.next;
6321                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6322                            {
6323                               if(slave.Create())
6324                                  // Things might have happened that invalidated 'next'...
6325                                  // Start over the search for slaves to create.
6326                                  // (Added this to fix crash with Stacker & Toolbar)
6327                                  next = slaves.first;
6328                            }
6329                         }
6330                      }
6331
6332                      if(OnPostCreate())
6333                         OnApplyGraphics();
6334
6335                      /*
6336                      if(parent == guiApp.desktop)
6337                         Log("Real SetState %s\n", caption);
6338                      */
6339
6340                      if(isActiveClient && visible)
6341                      {
6342                         parent.numPositions--;
6343                         if(state == minimized) parent.numIcons--;
6344                      }
6345
6346                      parent.OnChildAddedOrRemoved(this, false);
6347
6348                      if(rootWindow == this && visible)   // So that X11 windows don't show as 'unknown'
6349                         UpdateCaption();
6350                      // Real set state & activate for proper display & activation
6351                      property::visible = visible;
6352                      //  SetState(state & 0x00000003, true, 0);
6353                      guiApp.interfaceDriver.SetIcon(this, icon);
6354
6355                      if(visible)
6356                      {
6357                         UpdateCaption();
6358                         /*if(rootWindow == this)
6359                            guiApp.interfaceDriver.ActivateRootWindow(this);
6360                         else*/
6361                         if(creationActivation == activate && guiApp.desktop.active)
6362                            ActivateEx(true, false, true, true, null, null);
6363                         else if(creationActivation == activate || creationActivation == flash)
6364                         {
6365                            MakeActive();
6366                            if(this == rootWindow)
6367                               Flash();
6368                         }
6369                      }
6370
6371                      if(!destroyed)
6372                         rootWindow.ConsequentialMouseMove(false);
6373
6374                      result = true;
6375                   }
6376                }
6377             }
6378          }
6379          /*
6380          if(!result)
6381          {
6382             Destroy(0);
6383             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6384          }
6385          */
6386
6387          if(!result)
6388          {
6389             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6390             created = false;
6391             //style.hidden = true; // !visible;
6392             style.hidden = !visible;
6393             if(master.modalSlave == this)
6394                master.modalSlave = null;
6395          }
6396          delete this;
6397       }
6398       return result;
6399    }
6400
6401    void WriteCaption(Surface surface, int x, int y)
6402    {
6403       if(caption)
6404          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6405    }
6406
6407    void Update(Box region)
6408    {
6409       if(this)
6410       {
6411          Window rootWindow;
6412
6413          rootWindow = this.rootWindow;
6414
6415          // rootWindow.mutex.Wait();
6416          if(!destroyed && visible && display)
6417          {
6418             Window child;
6419             Box realBox;
6420
6421             // Testing this to avoid repetitve full update to take time...
6422             if(dirtyArea.count == 1)
6423             {
6424                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6425                if(item.box.left <= box.left &&
6426                   item.box.top <= box.top &&
6427                   item.box.right >= box.right &&
6428                   item.box.bottom >= box.bottom)
6429                {
6430                   rootWindow.dirty = true;
6431                   return;
6432                }
6433             }
6434
6435             if(display.flags.flipping && !rootWindow.dirty)
6436             {
6437                if(this == rootWindow)
6438                   region = null;
6439                else
6440                {
6441                   rootWindow.Update(null);
6442                   return;
6443                }
6444             }
6445
6446             rootWindow.dirty = true;
6447
6448             if(region != null)
6449             {
6450                realBox = region;
6451                realBox.left += clientStart.x;
6452                realBox.top += clientStart.y;
6453                realBox.right += clientStart.x;
6454                realBox.bottom += clientStart.y;
6455                realBox.Clip(box);
6456             }
6457             else
6458                realBox = box;
6459
6460             if(realBox.right >= realBox.left &&
6461                realBox.bottom >= realBox.top)
6462             {
6463                // if(!rootWindow.fullRender)
6464                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6465
6466                for(child = children.first; child; child = child.next)
6467                {
6468                   if(!child.is3D)
6469                   {
6470                      Box box = realBox;
6471                      box.left -= child.absPosition.x - absPosition.x;
6472                      box.top -= child.absPosition.y - absPosition.y;
6473                      box.right -= child.absPosition.x - absPosition.x;
6474                      box.bottom -= child.absPosition.y - absPosition.y;
6475                      if(box.right >= child.box.left && box.left <= child.box.right &&
6476                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6477                      {
6478                         box.left -= child.clientStart.x;
6479                         box.top -= child.clientStart.y;
6480                         box.right -= child.clientStart.x;
6481                         box.bottom -= child.clientStart.y;
6482                         child.Update(box);
6483                      }
6484                   }
6485                }
6486
6487                realBox.left += absPosition.x - rootWindow.absPosition.x;
6488                realBox.top += absPosition.y - rootWindow.absPosition.y;
6489                realBox.right += absPosition.x - rootWindow.absPosition.x;
6490                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6491                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6492             }
6493          }
6494          else if(this == guiApp.desktop)
6495          {
6496             Window window;
6497             for(window = children.first; window; window = window.next)
6498             {
6499                if(!window.is3D)
6500                {
6501                   if(region != null)
6502                   {
6503                      Box childBox = region;
6504
6505                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6506                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6507                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6508                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6509
6510                      window.Update(childBox);
6511                   }
6512                   else
6513                      window.Update(null);
6514                }
6515             }
6516          }
6517
6518          // rootWindow.mutex.Release();
6519       }
6520    }
6521
6522    bool Capture(void)
6523    {
6524       bool result = true;
6525       if(guiApp.windowCaptured != this)
6526       {
6527          if(guiApp.windowCaptured)
6528             result = false;
6529          else
6530          {
6531             //Logf("Captured %s (%s)\n", caption, class.name);
6532             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6533             guiApp.windowCaptured = this;
6534          }
6535       }
6536       return result;
6537    }
6538
6539    bool Destroy(int64 code)
6540    {
6541       //if(created)
6542       if(this)
6543       {
6544          if(!destroyed && !CloseConfirmation(false)) return false;
6545          incref this;
6546          if(DestroyEx(code))
6547          {
6548             // TOCHECK: Should autoCreate be set to false here?
6549             autoCreate = false;
6550             wasCreated = false;
6551             delete this;
6552             return true;
6553          }
6554          delete this;
6555       }
6556       return false;
6557    }
6558
6559    void Move(int x, int y, int w, int h)
6560    {
6561       normalAnchor = Anchor { left = x, top = y };
6562       normalSizeAnchor = SizeAnchor { size = { w, h } };
6563
6564       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6565       {
6566          if(destroyed) return;
6567
6568          stateAnchor = normalAnchor;
6569          stateSizeAnchor = normalSizeAnchor;
6570
6571          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6572          Position(x,y, w, h, true, true, true, true, false, true);
6573       }
6574    }
6575
6576    DialogResult Modal(void)
6577    {
6578       isModal = true;
6579       if(Create())
6580          return DoModal();
6581
6582       // FIXES MEMORY LEAK IF Create() FAILED
6583       incref this;
6584       delete this;
6585       return 0;
6586    }
6587
6588    void SetScrollArea(int width, int height, bool snapToStep)
6589    {
6590       if(snapToStep)
6591       {
6592          int stepX = sbStep.x, stepY = sbStep.y;
6593          // Needed to make snapped down position match the skin's check of client area
6594          // against realvirtual
6595          if(guiApp.textMode)
6596          {
6597             SNAPDOWN(stepX, textCellW);
6598             SNAPDOWN(stepY, textCellH);
6599             stepX = Max(stepX, textCellW);
6600             stepY = Max(stepY, textCellH);
6601          }
6602          if(scrollFlags.snapX)
6603             SNAPUP(width, stepX);
6604          if(scrollFlags.snapY)
6605             SNAPUP(height, stepY);
6606       }
6607
6608       reqScrollArea.w = width;
6609       reqScrollArea.h = height;
6610       noAutoScrollArea = (width > 0 || height > 0);
6611
6612       UpdateScrollBars(true, true);
6613    }
6614
6615    void SetScrollPosition(int x, int y)
6616    {
6617       if(sbh)
6618          sbh.Action(setPosition, x, 0);
6619       else
6620       {
6621          int range;
6622          int seen = clientSize.w, total = reqScrollArea.w;
6623          seen = Max(1,seen);
6624          if(scrollFlags.snapX)
6625             SNAPDOWN(seen, sbStep.x);
6626
6627          if(!total) total = seen;
6628          range = total - seen + 1;
6629          range = Max(range, 1);
6630          if(x < 0) x = 0;
6631          if(x >= range) x = range - 1;
6632
6633          if(scrollFlags.snapX)
6634             SNAPUP(x, sbStep.x);
6635
6636          if(scroll.x != x)
6637             OnHScroll(setPosition, x, 0);
6638
6639          if(guiApp.textMode)
6640          {
6641             SNAPDOWN(x, textCellW);
6642          }
6643          scroll.x = x;
6644       }
6645
6646       if(sbv)
6647          sbv.Action(setPosition, y, 0);
6648       else
6649       {
6650          int range;
6651          int seen = clientSize.h, total = reqScrollArea.h;
6652          seen = Max(1,seen);
6653
6654          if(scrollFlags.snapY)
6655             SNAPDOWN(seen, sbStep.y);
6656
6657          if(!total) total = seen;
6658          range = total - seen + 1;
6659          range = Max(range, 1);
6660          if(y < 0) y = 0;
6661          if(y >= range) y = range - 1;
6662
6663          if(scrollFlags.snapY)
6664             SNAPUP(y, sbStep.y);
6665
6666          if(scroll.y != y)
6667             OnVScroll(setPosition, y, 0);
6668          if(guiApp.textMode)
6669          {
6670             SNAPDOWN(y, textCellH);
6671          }
6672          scroll.y = y;
6673       }
6674       if(!sbh || !sbv)
6675          UpdateCaret(false, false);
6676    }
6677
6678    void SetScrollLineStep(int stepX, int stepY)
6679    {
6680       sbStep.x = stepX;
6681       sbStep.y = stepY;
6682       if(guiApp.textMode)
6683       {
6684          SNAPDOWN(stepX, textCellW);
6685          SNAPDOWN(stepY, textCellH);
6686          stepX = Max(stepX, textCellW);
6687          stepY = Max(stepY, textCellH);
6688       }
6689       if(sbh)
6690          sbh.lineStep = stepX;
6691       if(sbv)
6692          sbv.lineStep = stepY;
6693    }
6694
6695    void SetState(WindowState newState, bool activate, Modifiers mods)
6696    {
6697       if(created)
6698       {
6699          if(state == newState || OnStateChange(newState, mods))
6700          {
6701             //WindowState prevState = state;
6702
6703             StopMoving();
6704
6705             // This used to be at the end of the brackets... moved for X, testing...
6706             // This has the effect of activating the window through the system...
6707             if(rootWindow == this)
6708                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6709
6710             SetStateEx(newState, activate);
6711
6712             if(rootWindow == this && !rootWindow.nativeDecorations)
6713             {
6714                int x = position.x, y = position.y;
6715                /*if(style.interim)
6716                {
6717                   x -= guiApp.desktop.absPosition.x;
6718                   y -= guiApp.desktop.absPosition.y;
6719                }*/
6720                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6721             }
6722
6723             //state = newState;
6724             //state = prevState;
6725
6726             if(state != maximized && style.hasMaximize)
6727             {
6728                Window child;
6729                for(child = parent.children.first; child; child = child.next)
6730                {
6731                   if(child != this && child.state == maximized)
6732                      child.SetStateEx(normal, false);
6733                }
6734             }
6735
6736             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6737                parent.UpdateScrollBars(true, true);
6738
6739             /*
6740             // Do we really need this stuff here?
6741             // Shouldn't the Activate stuff take care of it?
6742             if(parent.rootWindow == parent && style)
6743             {
6744                char caption[2048];
6745                parent.FigureCaption(caption);
6746                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6747                parent.UpdateDecorations();
6748             }
6749             */
6750
6751             rootWindow.ConsequentialMouseMove(false);
6752          }
6753       }
6754       else
6755          state = newState;
6756    }
6757
6758    BitmapResource GetIcon(SkinBitmap iconID)
6759    {
6760       return guiApp.currentSkin.GetBitmap(iconID);
6761    }
6762
6763    void SetMouseRange(Box range)
6764    {
6765       if(range || guiApp.fullScreenMode)
6766       {
6767          Box clip;
6768          if(range != null)
6769          {
6770             clip.left   = range.left + absPosition.x + clientStart.x;
6771             clip.top    = range.top + absPosition.y + clientStart.y;
6772             clip.right  = range.right + absPosition.x + clientStart.x;
6773             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6774          }
6775          else
6776          {
6777             clip.left   = guiApp.desktop.box.left;
6778             clip.top    = guiApp.desktop.box.top;
6779             clip.right  = guiApp.desktop.box.right;
6780             clip.bottom = guiApp.desktop.box.bottom;
6781          }
6782          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6783       }
6784       else
6785          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6786    }
6787
6788    void SetMouseRangeToClient(void)
6789    {
6790       if(guiApp.fullScreenMode || this != guiApp.desktop)
6791       {
6792          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6793          box.Clip(clientArea);
6794          SetMouseRange(box);
6795       }
6796       else
6797          SetMouseRange(null);
6798    }
6799
6800    void SetMouseRangeToWindow(void)
6801    {
6802       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6803       if(this == guiApp.desktop)
6804          SetMouseRangeToClient();
6805       else
6806          SetMouseRange(box);
6807    }
6808
6809    // x, y: Desktop Coordinates
6810    void ShowSysMenu(int x, int y)
6811    {
6812       Menu menu { };
6813       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6814       MenuItem
6815       {
6816          menu, $"Restore", r, NotifySelect = MenuWindowRestore,
6817          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6818       };
6819       MenuItem
6820       {
6821          menu, $"Move", m, NotifySelect = MenuWindowMove,
6822          disabled = !style.fixed || state == maximized
6823       };
6824       MenuItem
6825       {
6826          menu, $"Size", s, NotifySelect = MenuWindowSize,
6827          disabled = !style.sizable || state != normal
6828       };
6829       MenuItem
6830       {
6831          menu, $"Minimize", n, NotifySelect = MenuWindowMinimize,
6832          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6833       };
6834       MenuItem
6835       {
6836          menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize,
6837          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6838       };
6839       MenuItem
6840       {
6841          menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop,
6842          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6843       };
6844       MenuDivider { menu };
6845       MenuItem
6846       {
6847          menu, $"Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6848          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6849       };
6850       windowMenu.Create();
6851    }
6852
6853    void Activate(void)
6854    {
6855       ActivateEx(true, true, true, true, null, null);
6856    }
6857
6858    void MakeActive(void)
6859    {
6860       ActivateEx(true, false, true, false, null, null);
6861    }
6862
6863    void SoftActivate(void)
6864    {
6865       if(guiApp.desktop.active)
6866          Activate();
6867       else if(!active)
6868       {
6869          MakeActive();
6870          if(this == rootWindow)
6871             Flash();
6872       }
6873    }
6874
6875    void Deactivate(void)
6876    {
6877       ActivateEx(false, true, true, true, null, null);
6878    }
6879
6880    void Flash(void)
6881    {
6882       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6883    }
6884
6885    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6886    {
6887       bool result = false;
6888       if(activeChild && activeChild.cycle)
6889       {
6890          Window modalWindow, child = activeChild;
6891          if(!clientOnly /*&& parent.tabCycle*/)
6892          {
6893             Window next = child;
6894             while(true)
6895             {
6896                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6897                {
6898                   if(cycleParents)
6899                   {
6900                      if(parent && parent.CycleChildren(backward, false, true, true))
6901                         return true;
6902                      break;
6903                   }
6904                   else
6905                      return false;
6906                }
6907                if(backward)
6908                   next = next.cycle.prev.data;
6909                else
6910                   next = next.cycle.next.data;
6911                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6912                   break;
6913             }
6914          }
6915          /*
6916          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) &&
6917             parent.tabCycle && parent.CycleChildren(backward, false, false))
6918             return true;
6919          */
6920
6921          if(tabCycleOnly && !tabCycle) return false;
6922
6923          while(child)
6924          {
6925             while(true)
6926             {
6927                if(backward)
6928                   child = child.cycle.prev.data;
6929                else
6930                   child = child.cycle.next.data;
6931                if(child == child.parent.activeChild)
6932                   return result;
6933                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6934                   break;
6935             }
6936             modalWindow = child.FindModal();
6937             if(!modalWindow)
6938             {
6939                // Scroll the window to include the active control
6940                if(sbh && !child.style.dontScrollHorz)
6941                {
6942                   if(child.scrolledPos.x < 0)
6943                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6944                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6945                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6946                }
6947                if(sbv && !child.style.dontScrollVert)
6948                {
6949                   if(child.scrolledPos.y < 0)
6950                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6951                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6952                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6953                }
6954             }
6955             result = true;
6956             child = modalWindow ? modalWindow : child;
6957             child.ActivateEx(true, true, true, true, null, null);
6958             if(child.tabCycle && child.childrenCycle.first)
6959                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6960             else
6961                break;
6962          }
6963       }
6964       else
6965          return false;
6966
6967       ConsequentialMouseMove(false);
6968       return result;
6969    }
6970
6971    void AddResource(Resource resource)
6972    {
6973       if(resource)
6974       {
6975          ResPtr ptr { resource = resource };
6976          resources.Add(ptr);
6977          incref resource;
6978
6979          // Load Graphics here if window is created already
6980          if(/*created && */display)
6981          {
6982             display.Lock(false);
6983             if(!ptr.loaded)   // This check prevents a leak in case a watcher on 'font' calls AddResource (ListBox FontResource leak)
6984                ptr.loaded = display.displaySystem.LoadResource(resource);
6985             display.Unlock();
6986          }
6987          /*
6988          // Temporary hack to load font right away for listbox in dropbox ...
6989          else if(master && master.display)
6990          {
6991             master.display.Lock(false);
6992             master.display.displaySystem.LoadResource(resource);
6993             master.display.Unlock();
6994          }
6995          */
6996       }
6997    }
6998
6999    void RemoveResource(Resource resource)
7000    {
7001       if(resource)
7002       {
7003          ResPtr ptr;
7004          for(ptr = resources.first; ptr; ptr = ptr.next)
7005          {
7006             if(ptr.resource == resource)
7007                break;
7008          }
7009
7010          if(ptr)
7011          {
7012             // Unload Graphics here if window is created already
7013             if(/*created && */display)
7014             {
7015                if(ptr.loaded)
7016                {
7017                   display.Lock(false);
7018                   display.displaySystem.UnloadResource(resource, ptr.loaded);
7019                   display.Unlock();
7020                   ptr.loaded = null;
7021                }
7022             }
7023             delete resource;
7024             resources.Delete(ptr);
7025          }
7026       }
7027    }
7028
7029    void SetCaret(int x, int y, int size)
7030    {
7031       if(!destroyed)
7032       {
7033          caretPos.x = x;
7034          caretPos.y = y;
7035          caretSize = size;
7036          if(active && !style.interim && isEnabled)
7037          {
7038             if(visible || !guiApp.caretOwner)
7039                guiApp.caretOwner = size ? this : null;
7040             if(size)
7041                UpdateCaret(false, false);
7042             else
7043             {
7044                guiApp.interfaceDriver.SetCaret(0,0,0);
7045                UpdateCaret(false, true);
7046                guiApp.caretEnabled = false;
7047             }
7048          }
7049          else if(style.inactive && active)
7050          {
7051             guiApp.interfaceDriver.SetCaret(0,0,0);
7052             UpdateCaret(false, true);
7053             guiApp.caretEnabled = false;
7054          }
7055       }
7056    }
7057
7058    void Scroll(int x, int y)
7059    {
7060       bool opaque = !style.drawBehind || background.a;
7061       if(opaque && display && display.flags.scrolling)
7062       {
7063          Box box = clientArea;
7064          box.left += clientStart.x;
7065          box.top += clientStart.y;
7066          box.right += clientStart.x;
7067          box.bottom += clientStart.y;
7068
7069          //scrollExtent.Free(null);
7070          scrollExtent.AddBox(box);
7071          scrolledArea.x += x;
7072          scrolledArea.y += y;
7073
7074          //scrollExtent.Free();
7075          //scrollExtent.AddBox(clientArea);
7076          //scrollExtent.Offset(clientStart.x, clientStart.y);
7077          //scrolledArea.x = x;
7078          //scrolledArea.y = y;
7079       }
7080       else
7081          Update(clientArea);
7082
7083       if(rootWindow)
7084          rootWindow.dirty = true;
7085    }
7086
7087    void ReleaseCapture()
7088    {
7089       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
7090       {
7091          Window oldCaptured = guiApp.windowCaptured;
7092          guiApp.windowCaptured = null;
7093          guiApp.prevWindow = null;
7094          incref oldCaptured;
7095
7096          //guiApp.Log("Released Capture\n");
7097
7098          guiApp.interfaceDriver.SetMouseCapture(null);
7099
7100          //oldCaptured.OnMouseCaptureLost();
7101
7102          if(oldCaptured)
7103             oldCaptured.ConsequentialMouseMove(false);
7104          delete oldCaptured;
7105       }
7106    }
7107
7108    private void _SetCaption(const char * format, va_list args)
7109    {
7110       if(this)
7111       {
7112          delete caption;
7113          if(format)
7114          {
7115             char caption[MAX_F_STRING];
7116             vsnprintf(caption, sizeof(caption), format, args);
7117             caption[sizeof(caption)-1] = 0;
7118
7119             this.caption = CopyString(caption);
7120          }
7121          if(created)
7122             UpdateCaption();
7123
7124          firewatchers caption;
7125       }
7126    }
7127
7128    /*deprecated*/ void SetText(const char * format, ...)
7129    {
7130       va_list args;
7131       va_start(args, format);
7132       _SetCaption(format, args);
7133       va_end(args);
7134    }
7135
7136    void SetCaption(const char * format, ...)
7137    {
7138       va_list args;
7139       va_start(args, format);
7140       _SetCaption(format, args);
7141       va_end(args);
7142    }
7143
7144    bool Grab(Bitmap bitmap, Box box, bool decorations)
7145    {
7146       bool result = false;
7147       if(display || this == guiApp.desktop)
7148       {
7149          Box clip = {MININT, MININT, MAXINT, MAXINT};
7150
7151          if(box != null)
7152             clip = box;
7153
7154          if(!decorations)
7155             clip.Clip(clientArea);
7156          else
7157             clip.Clip(this.box);
7158
7159          if(rootWindow != this)
7160          {
7161             clip.left   += absPosition.y;
7162             clip.top    += absPosition.y;
7163             clip.right  += absPosition.x;
7164             clip.bottom += absPosition.y;
7165          }
7166
7167          clip.left += decorations ? 0 : clientStart.x;
7168          clip.top += decorations ? 0 : clientStart.y;
7169          clip.right += decorations ? 0 : clientStart.x;
7170          clip.bottom += decorations ? 0 : clientStart.y;
7171
7172          if(display && display.flags.flipping)
7173          {
7174             rootWindow.Update(null);
7175             rootWindow.UpdateDisplay();
7176          }
7177
7178          if(!display)
7179          {
7180             Window window { };
7181             window.Create();
7182             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top,
7183                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7184             delete window;
7185          }
7186          else
7187             result = display.Grab(bitmap, clip.left, clip.top,
7188                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7189
7190          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7191          {
7192             if(!bitmap.Convert(null, pixelFormat888, null))
7193                result = false;
7194          }
7195       }
7196       return result;
7197    }
7198
7199    void GetMousePosition(int * x, int * y)
7200    {
7201       int mouseX = 0, mouseY = 0;
7202       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7203       {
7204          if(guiApp.driver)
7205             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7206          if(this != guiApp.desktop)
7207          {
7208             mouseX -= absPosition.x + clientStart.x;
7209             mouseY -= absPosition.y + clientStart.y;
7210          }
7211       }
7212       if(x) *x = mouseX;
7213       if(y) *y = mouseY;
7214    }
7215
7216    DialogResult DoModal()
7217    {
7218       DialogResult returnCode = 0;
7219       int terminated = terminateX;
7220       isModal = true;
7221       incref this;
7222       while(!destroyed && guiApp.driver != null)
7223       {
7224          if(terminateX != terminated)
7225          {
7226             terminated = terminateX;
7227             guiApp.desktop.Destroy(0);
7228             if(guiApp.desktop.created)
7229             {
7230                terminated = 0;
7231                //printf("Resetting terminate X to 0\n");
7232                terminateX = 0;
7233             }
7234             break;
7235          }
7236
7237          guiApp.UpdateDisplay();
7238          if(!guiApp.ProcessInput(false))
7239             guiApp.Wait();
7240       }
7241       returnCode = this.returnCode;
7242       delete this;
7243       return returnCode;
7244    }
7245
7246    void DoModalStart()
7247    {
7248       isModal = true;
7249       incref this;
7250    }
7251
7252    bool DoModalLoop()
7253    {
7254       return !destroyed && guiApp.driver != null && terminateX < 2;
7255    }
7256
7257    DialogResult DoModalEnd()
7258    {
7259       DialogResult returnCode = this.returnCode;
7260       delete this;
7261       return returnCode;
7262    }
7263
7264    // --- Window manipulation ---
7265    /*bool GetDisabled()
7266    {
7267       bool disabled = this.disabled;
7268       Window window;
7269       for(window = this; (window = window.master); )
7270       {
7271          if(window.disabled)
7272          {
7273             disabled = true;
7274             break;
7275          }
7276       }
7277       return disabled;
7278    }*/
7279
7280    // --- Mouse Manipulation ---
7281    void GetNCMousePosition(int * x, int * y)
7282    {
7283       GetMousePosition(x, y);
7284       if(x) *x += clientStart.x;
7285       if(y) *y += clientStart.y;
7286    }
7287
7288    // --- Carets manipulation ---
7289    void GetCaretPosition(Point caretPos)
7290    {
7291       caretPos = this.caretPos;
7292    }
7293
7294    int GetCaretSize(void)
7295    {
7296       return caretSize;
7297    }
7298
7299    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7300    {
7301       Destroy(button.id);
7302       return true;
7303    }
7304
7305    bool CloseConfirmation(bool parentClosing)
7306    {
7307       bool result = true;
7308       OldLink slave;
7309       Window child;
7310
7311       if(closing)
7312          return false;
7313       if(terminateX > 1)
7314          return true;
7315
7316       closing = true;
7317
7318       if(!OnClose(parentClosing))
7319          result = false;
7320
7321       // If you want to skip this, simply set modifiedDocument to false in OnClose
7322       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7323       {
7324          DialogResult dialogRes;
7325          char message[1024];
7326          if(fileName)
7327             sprintf(message, $"Save changes to %s?", fileName);
7328          else
7329             sprintf(message, $"Save changes to Untitled %d?", documentID);
7330
7331          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7332
7333          if(dialogRes == yes)
7334          {
7335             // TOFIX: Precomp error if brackets are taken out
7336             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7337          }
7338          else if(dialogRes == cancel)
7339             result = false;
7340       }
7341
7342       if(result)
7343       {
7344          for(slave = slaves.first; slave; slave = slave.next)
7345          {
7346             Window w = slave.data;
7347             if(w.parent != this && !w.IsDescendantOf(this) && !w.CloseConfirmation(true))
7348             {
7349                result = false;
7350                break;
7351             }
7352          }
7353       }
7354
7355       // Confirm closure of active clients first (We use OnClose() to hide instead of destroy in the IDE)
7356       if(result)
7357       {
7358          for(child = children.first; child; child = child.next)
7359             if(child.isActiveClient && !child.CloseConfirmation(true))
7360             {
7361                result = false;
7362                break;
7363             }
7364       }
7365       if(result)
7366       {
7367          for(child = children.first; child; child = child.next)
7368             if(!child.isActiveClient && !child.CloseConfirmation(true))
7369             {
7370                result = false;
7371                break;
7372             }
7373       }
7374       closing = false;
7375       return result;
7376    }
7377
7378    // Static methods... move them somewhere else?
7379    void ::RestoreCaret()
7380    {
7381       if(guiApp.caretOwner)
7382          guiApp.caretOwner.UpdateCaret(false, false);
7383    }
7384
7385    void ::FreeMouseRange()
7386    {
7387       guiApp.interfaceDriver.SetMouseRange(null, null);
7388    }
7389
7390    // Menu Methods
7391    bool MenuFileClose(MenuItem selection, Modifiers mods)
7392    {
7393       Window document = activeChild;
7394       if(document)
7395          document.Destroy(0);
7396       return true;
7397    }
7398
7399    bool MenuFileExit(MenuItem selection, Modifiers mods)
7400    {
7401       Destroy(0);
7402       return true;
7403    }
7404
7405    bool MenuFileSave(MenuItem selection, Modifiers mods)
7406    {
7407       SetupFileMonitor();
7408       if(fileName)
7409       {
7410          fileMonitor.fileName = null;
7411          saving = true;
7412
7413          if(OnSaveFile(fileName))
7414          {
7415             //if(OnFileModified != Window::OnFileModified)
7416             {
7417                saving = false;
7418                fileMonitor.fileName = fileName;
7419             }
7420             return true;
7421          }
7422          else
7423          {
7424             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7425             DialogResult answer = dialog.Modal();
7426             saving = false;
7427             if(answer != yes) return (bool)answer;
7428          }
7429       }
7430       return MenuFileSaveAs(selection, mods);
7431    }
7432
7433    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7434    {
7435       DialogResult result = (DialogResult)bool::true;
7436       FileDialog fileDialog = saveDialog;
7437
7438       SetupFileMonitor();
7439
7440       if(!fileDialog)
7441          fileDialog = FileDialog {};
7442       if(fileDialog)
7443       {
7444          incref fileDialog;
7445          if(fileName)
7446             fileDialog.filePath = fileName;
7447          else
7448          {
7449             char filePath[MAX_FILENAME];
7450             sprintf(filePath, "Untitled %d", documentID);
7451             fileDialog.filePath = filePath;
7452          }
7453          fileMonitor.fileName = null;
7454
7455          fileDialog.type = save;
7456          fileDialog.text = $"Save As";
7457
7458          while(true)
7459          {
7460             fileDialog.master = master.parent ? master : this;
7461             if(fileDialog.Modal() == ok)
7462             {
7463                const char * filePath = fileDialog.filePath;
7464                saving = true;
7465                if(OnSaveFile(filePath))
7466                {
7467                   saving = false;
7468                   property::fileName = filePath;
7469                   NotifySaved(master, this, filePath);
7470                   break;
7471                }
7472                else
7473                {
7474                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7475                   DialogResult answer = dialog.Modal();
7476                   saving = false;
7477                   if(answer != yes)
7478                   {
7479                      result = answer;
7480                      break;
7481                   }
7482                }
7483             }
7484             else
7485             {
7486                result = cancel;
7487                break;
7488             }
7489          }
7490          //if(OnFileModified != Window::OnFileModified && fileName)
7491          {
7492             if(fileName)
7493                fileMonitor.fileName = fileName;
7494          }
7495          delete fileDialog;
7496       }
7497       return (bool)result; // Actually returning result from Yes/NoCancel message box
7498    }
7499
7500    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7501    {
7502       Window document = activeChild;
7503       Window next;
7504       for(document = children.first; document; document = next)
7505       {
7506          next = document.next;
7507          if(document.style.isDocument || document.fileName)
7508             document.MenuFileSave(selection, mods);
7509       }
7510       return true;
7511    }
7512
7513    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7514    {
7515       Window document;
7516
7517       for(document = children.first; document; document = document.next)
7518          //if(document.style.isDocument && document.state == minimized)
7519          if(document.style.isActiveClient && document.state == minimized)
7520             document.SetState(minimized, false, mods);
7521       return true;
7522    }
7523
7524    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7525    {
7526       Window document = activeChild;
7527       if(document)
7528       {
7529          Window firstDocument = null;
7530          Window child;
7531          OldLink cycle = document.cycle.prev;
7532          int id = 0;
7533          while(true)
7534          {
7535             child = cycle.data;
7536             if(child.style.isActiveClient && !child.style.hidden)
7537             {
7538                Window last;
7539
7540                firstDocument = child;
7541                if(child.state == minimized)
7542                   child.SetState(minimized, false, mods);
7543                else
7544                {
7545                   child.positionID = id++;
7546                   child.SetState(normal, false, mods);
7547                   child.anchor.left.type = cascade;
7548                   {
7549                      int x, y, w, h;
7550                      child.normalSizeAnchor = *&child.sizeAnchor;
7551                      child.normalAnchor = child.anchor;
7552
7553                      // Break the anchors for moveable/resizable windows
7554                      if(child.style.fixed)
7555                      {
7556                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7557
7558                         (*&child.normalAnchor).left = x;
7559                         (*&child.normalAnchor).top = y;
7560                         (*&child.normalAnchor).right.type = none;
7561                         (*&child.normalAnchor).bottom.type = none;
7562
7563                         child.normalSizeAnchor.isClientW = false;
7564                         child.normalSizeAnchor.isClientH = false;
7565                         child.normalSizeAnchor.size.w = w;
7566                         child.normalSizeAnchor.size.h = h;
7567                         child.anchored = false;
7568                      }
7569
7570                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7571                      {
7572                         child.stateAnchor = child.normalAnchor;
7573                         child.stateSizeAnchor = child.normalSizeAnchor;
7574
7575                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7576                         child.Position(x, y, w, h, true, true, true, true, false, false);
7577                      }
7578                   }
7579                }
7580
7581                last = children.last;
7582                if(!child.style.stayOnTop)
7583                   for(; last && last.style.stayOnTop; last = last.prev);
7584                children.Move(child, last);
7585                childrenOrder.Move(child.order, childrenOrder.last);
7586             }
7587             if(cycle == document.cycle) break;
7588             cycle = cycle.prev;
7589          }
7590          if(firstDocument)
7591             firstDocument.Activate();
7592       }
7593       return true;
7594    }
7595
7596    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7597    {
7598       if(style.hasClose)
7599          Destroy(0);
7600       return true;
7601    }
7602
7603    // Close all closes all active clients, not all documents
7604    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7605    {
7606       Window next, document;
7607
7608       for(document = children.first; document; document = next)
7609       {
7610          for(next = document.next; next && !next.style.isActiveClient; next = next.next);
7611          if(document.style.isActiveClient)
7612             if(!document.Destroy(0) && !document.style.hidden)
7613                return false;
7614       }
7615       return true;
7616    }
7617
7618    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7619    {
7620       if(style.hasMaximize && state != maximized)
7621          SetState(maximized, 0, 0);
7622       return true;
7623    }
7624
7625    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7626    {
7627       if(style.hasMinimize && state != minimized)
7628       {
7629          SetState(minimized, 0, 0);
7630          parent.CycleChildren(false, true, false, true);
7631       }
7632       return true;
7633    }
7634
7635    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7636    {
7637       MenuMoveOrSize(false, selection ? true : false);
7638       return true;
7639    }
7640
7641    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7642    {
7643       CycleChildren(false, true, false, true);
7644       return true;
7645    }
7646
7647    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7648    {
7649       CycleChildren(true, true, false, true);
7650       return true;
7651    }
7652
7653    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7654    {
7655       MenuMoveOrSize(true, true);
7656       return true;
7657    }
7658
7659    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7660    {
7661       if(state != normal)
7662          SetState(normal, 0, 0);
7663       return true;
7664    }
7665
7666    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7667    {
7668       Window document;
7669       int64 id = selection.id;
7670       OldLink cycle = activeClient.cycle;
7671       int c = 0;
7672       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7673       while(true)
7674       {
7675          Window sibling = cycle.data;
7676          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7677          {
7678             if(c == id)
7679                break;
7680             c++;
7681          }
7682          cycle = cycle.next;
7683       }
7684       document = cycle.data;
7685       document.Activate();
7686
7687       //if(activeChild.state == maximized)
7688       //  document.SetState(maximized, false, mods);
7689       //else if(document.state == minimized)
7690       //   document.SetState(normal, false, mods);
7691       return true;
7692    }
7693
7694    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7695    {
7696       stayOnTop = !style.stayOnTop;
7697       return true;
7698    }
7699
7700    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7701    {
7702       Window document = activeChild;
7703       if(document)
7704       {
7705          Window firstDocument = null;
7706          OldLink cycle = document.cycle;
7707          int id = 0;
7708          while(true)
7709          {
7710             Window child = cycle.data;
7711             if(child.style.isActiveClient && !child.style.hidden)
7712             {
7713                if(!firstDocument) firstDocument = child;
7714                if(child.state == minimized)
7715                   child.SetState(minimized, false, mods);
7716                else
7717                {
7718                   child.positionID = id++;
7719                   child.SetState(normal, false, mods);
7720                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7721
7722                   child.anchor.left.type = hTiled;
7723                   {
7724                      int x, y, w, h;
7725                      child.normalSizeAnchor = *&child.sizeAnchor;
7726                      child.normalAnchor = child.anchor;
7727
7728                      // Break the anchors for moveable/resizable windows
7729                      if(child.style.fixed)
7730                      {
7731                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7732
7733                         (*&child.normalAnchor).left = x;
7734                         (*&child.normalAnchor).top = y;
7735                         (*&child.normalAnchor).right.type = none;
7736                         (*&child.normalAnchor).bottom.type = none;
7737                         child.normalSizeAnchor.isClientW = false;
7738                         child.normalSizeAnchor.isClientH = false;
7739                         child.normalSizeAnchor.size.w = w;
7740                         child.normalSizeAnchor.size.h = h;
7741                         child.anchored = false;
7742                      }
7743
7744                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7745                      {
7746                         child.stateAnchor = child.normalAnchor;
7747                         child.stateSizeAnchor = child.normalSizeAnchor;
7748
7749                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7750                         child.Position(x,y, w, h, true, true, true, true, false, true);
7751                      }
7752                   }
7753                }
7754             }
7755             if((cycle = cycle.next) == document.cycle) break;
7756          }
7757          if(firstDocument)
7758             firstDocument.Activate();
7759       }
7760       return true;
7761    }
7762
7763    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7764    {
7765       Window document = activeChild;
7766       if(document)
7767       {
7768          Window firstDocument = null;
7769          Window child;
7770          OldLink cycle = document.cycle;
7771          int id = 0;
7772          while(true)
7773          {
7774             child = cycle.data;
7775             //if(child.style.isDocument)
7776             if(child.style.isActiveClient && !child.style.hidden)
7777             {
7778                if(!firstDocument) firstDocument = child;
7779                if(child.state == minimized)
7780                   child.SetState(minimized, false, mods);
7781                else
7782                {
7783                   child.positionID = id++;
7784                   child.SetState(normal, false, mods);
7785                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7786
7787                   child.anchor.left.type = vTiled;
7788                   {
7789                      int x, y, w, h;
7790                      child.normalSizeAnchor = *&child.sizeAnchor;
7791                      child.normalAnchor = child.anchor;
7792
7793                      // Break the anchors for moveable/resizable windows
7794                      if(child.style.fixed)
7795                      {
7796                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7797
7798                         (*&child.normalAnchor).left = x;
7799                         (*&child.normalAnchor).top = y;
7800                         (*&child.normalAnchor).right.type = none;
7801                         (*&child.normalAnchor).bottom.type = none;
7802                         child.normalSizeAnchor.isClientW = false;
7803                         child.normalSizeAnchor.isClientH = false;
7804                         child.normalSizeAnchor.size.w = w;
7805                         child.normalSizeAnchor.size.h = h;
7806                         child.anchored = false;
7807                      }
7808
7809                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7810                      {
7811                         child.stateAnchor = child.normalAnchor;
7812                         child.stateSizeAnchor = child.normalSizeAnchor;
7813
7814                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7815                         child.Position(x,y, w, h, true, true, true, true, false, true);
7816                      }
7817                   }
7818                }
7819             }
7820             if((cycle = cycle.next) == document.cycle) break;
7821          }
7822          if(firstDocument)
7823             firstDocument.Activate();
7824       }
7825       return true;
7826    }
7827
7828    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7829    {
7830       WindowList dialog { master = this };
7831       Window document = (Window)(intptr)dialog.Modal();
7832       if(document)
7833       {
7834          if(activeChild.state == maximized)
7835             document.SetState(maximized, false, mods);
7836          else if(document.state == minimized)
7837             document.SetState(normal, false, mods);
7838          document.Activate();
7839       }
7840       return true;
7841    }
7842
7843    // Virtual Methods
7844    virtual bool OnCreate(void);
7845    virtual void OnDestroy(void);
7846    virtual void OnDestroyed(void);
7847    virtual bool OnClose(bool parentClosing);
7848    virtual bool OnStateChange(WindowState state, Modifiers mods);
7849    virtual bool OnPostCreate(void);
7850    virtual bool OnMoving(int *x, int *y, int w, int h);
7851    virtual bool OnResizing(int *width, int *height);
7852    virtual void OnResize(int width, int height);
7853    virtual void OnPosition(int x, int y, int width, int height);
7854    virtual bool OnLoadGraphics(void);
7855    virtual void OnApplyGraphics(void);
7856    virtual void OnUnloadGraphics(void);
7857    virtual void OnRedraw(Surface surface);
7858    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7859    virtual void OnActivateClient(Window client, Window previous);
7860    virtual bool OnKeyDown(Key key, unichar ch);
7861    virtual bool OnKeyUp(Key key, unichar ch);
7862    virtual bool OnKeyHit(Key key, unichar ch);
7863    virtual bool OnSysKeyDown(Key key, unichar ch);
7864    virtual bool OnSysKeyUp(Key key, unichar ch);
7865    virtual bool OnSysKeyHit(Key key, unichar ch);
7866    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7867    virtual bool OnMouseLeave(Modifiers mods);
7868    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7869    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7870    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7871    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7872    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7873    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7874    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7875    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7876    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7877    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7878    virtual void OnMouseCaptureLost(void);
7879    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7880    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7881    virtual void OnDrawOverChildren(Surface surface);
7882    virtual bool OnFileModified(FileChange fileChange, const char * param);
7883    virtual bool OnSaveFile(const char * fileName);
7884
7885    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
7886    // Note: A 'client' would refer to isActiveClient, rather than
7887    // being confined to the 'client area' (nonClient == false)
7888    virtual void OnChildAddedOrRemoved(Window child, bool removed);
7889    virtual void OnChildVisibilityToggled(Window child, bool visible);
7890    virtual void OnChildResized(Window child, int x, int y, int w, int h);
7891
7892    // Skins Virtual Functions
7893    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7894    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7895    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7896    {
7897       *cw = *w;
7898       *ch = *h;
7899    }
7900    virtual void ShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
7901    virtual void PreShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
7902    virtual bool IsMouseMoving(int x, int y, int w, int h)
7903    {
7904       return false;
7905    }
7906    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
7907    {
7908       return false;
7909    }
7910    virtual void UpdateNonClient();
7911    virtual void SetBox(Box box);    // This is used in the MySkin skin
7912    virtual bool IsInside(int x, int y)
7913    {
7914       return box.IsPointInside({x, y});
7915    }
7916    virtual bool IsOpaque()
7917    {
7918       return (!style.drawBehind || background.a == 255);
7919    }
7920
7921    // Notifications
7922    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7923    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7924    virtual void Window::NotifySaved(Window window, const char * filePath);
7925
7926    // Public Methods
7927
7928    // Properties
7929    property Window parent
7930    {
7931       property_category $"Layout"
7932       set
7933       {
7934          if(value || guiApp.desktop)
7935          {
7936             Window last;
7937             Window oldParent = parent;
7938             Anchor anchor = this.anchor;
7939
7940             if(value && value.IsDescendantOf(this)) return;
7941             if(value && value == this)
7942                return;
7943             if(!value) value = guiApp.desktop;
7944
7945             if(value == oldParent) return;
7946
7947             if(!master || (master == this.parent && master == guiApp.desktop))
7948                property::master = value;
7949
7950             if(parent)
7951             {
7952                parent.children.Remove(this);
7953
7954                parent.Update(
7955                {
7956                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7957                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7958                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7959                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7960                });
7961             }
7962
7963             last = value.children.last;
7964
7965             if(style.isDocument)
7966             {
7967                if(parent)
7968                   parent.numDocuments--;
7969                documentID = value.GetDocumentID();
7970             }
7971
7972             if(style.isActiveClient && !style.hidden)
7973             {
7974                if(parent && parent != guiApp.desktop && !(style.hidden))
7975                {
7976                   if(state == minimized) parent.numIcons--;
7977                   parent.numPositions--;
7978                }
7979             }
7980
7981             if(!style.stayOnTop)
7982                for(; last && last.style.stayOnTop; last = last.prev);
7983
7984             value.children.Insert(last, this);
7985
7986             // *** NEW HERE: ***
7987             if(cycle)
7988                parent.childrenCycle.Delete(cycle);
7989             if(order)
7990                parent.childrenOrder.Delete(order);
7991             cycle = null;
7992             order = null;
7993             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
7994             //           Should something else be done?
7995             if(parent && parent.activeChild == this)
7996                parent.activeChild = null;
7997             if(parent && parent.activeClient == this)
7998                parent.activeClient = null;
7999
8000             //if(created)
8001             {
8002                if(created)
8003                {
8004                   int x = position.x, y = position.y, w = size.w, h = size.h;
8005
8006                   int vpw, vph;
8007
8008                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
8009                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
8010
8011                   vpw = value.clientSize.w;
8012                   vph = value.clientSize.h;
8013                   if(style.nonClient)
8014                   {
8015                      vpw = value.size.w;
8016                      vph = value.size.h;
8017                   }
8018                   else if(style.fixed)
8019                   {
8020                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
8021                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
8022                   }
8023
8024                   anchor = this.anchor;
8025
8026                   if(anchor.left.type == offset)            anchor.left.distance = x;
8027                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
8028                   if(anchor.top.type == offset)             anchor.top.distance = y;
8029                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
8030                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
8031                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
8032                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
8033                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
8034                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
8035                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
8036
8037                   if(!anchor.left.type && !anchor.right.type)
8038                   {
8039                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
8040                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
8041                   }
8042                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
8043                   if(!anchor.top.type && !anchor.bottom.type)
8044                   {
8045                      anchor.vert.distance = (y + h / 2) - (vph / 2);
8046                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
8047                   }
8048                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
8049                }
8050                parent = value;
8051                parent.OnChildAddedOrRemoved(this, false);
8052
8053                // *** NEW HERE ***
8054                if(!style.inactive)
8055                {
8056                   if(!style.noCycle)
8057                      parent.childrenCycle.Insert(
8058                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8059                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8060                         null,
8061                         cycle = OldLink { data = this });
8062                   parent.childrenOrder.Insert(
8063                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8064                      order = OldLink { data = this });
8065                }
8066
8067                if(!style.hidden && style.isActiveClient)
8068                {
8069                   positionID = parent.GetPositionID(this);
8070                   parent.numPositions++;
8071                   if(state == minimized) parent.numIcons--;
8072                }
8073
8074                // *** FONT INHERITANCE ***
8075                if(!setFont && oldParent)
8076                   stopwatching(oldParent, font);
8077
8078                if(systemFont)
8079                {
8080                   RemoveResource(systemFont);
8081                   delete systemFont;
8082                }
8083                // TESTING WITH WATCHERS:
8084                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8085                // usedFont = setFont ? setFont : (systemFont);
8086
8087                if(!usedFont)
8088                {
8089                   if(guiApp.currentSkin)
8090                   {
8091                      systemFont = guiApp.currentSkin.SystemFont();
8092                      incref systemFont;
8093                   }
8094                   usedFont = systemFont;
8095                   AddResource(systemFont);
8096                }
8097
8098                if(!setFont)
8099                   watch(value)
8100                   {
8101                      font
8102                      {
8103                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8104                         firewatchers font;
8105                         Update(null);
8106                      }
8107                   };
8108
8109                firewatchers font;
8110
8111
8112                if(value.rootWindow && value.rootWindow.display && rootWindow && created)
8113                {
8114                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) ||
8115                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
8116
8117                   if(reloadGraphics)
8118                      UnloadGraphics(false);
8119                   SetupDisplay();
8120                   if(reloadGraphics)
8121                      LoadGraphics(false, false);
8122
8123                   /*
8124                   if(value.rootWindow != rootWindow)
8125                      DisplayModeChanged();
8126                   else
8127                   */
8128                }
8129                scrolledPos.x = MININT; // Prevent parent update
8130                {
8131                   bool anchored = this.anchored;
8132                   property::anchor = anchor;
8133                   this.anchored = anchored;
8134                }
8135                /*
8136                {
8137                   int x, y, w, h;
8138                   if(guiApp.currentSkin)
8139                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
8140
8141                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8142                   Position(x, y, w, h, true, true, true, true, false, true);
8143                }
8144                */
8145
8146             }
8147             // else parent = value;
8148             if(oldParent)
8149                oldParent.OnChildAddedOrRemoved(this, true);
8150          }
8151       }
8152       get { return parent; }
8153    };
8154
8155    property Window master
8156    {
8157       property_category $"Behavior"
8158       set
8159       {
8160          //if(this == value) return;
8161          if(value && value.IsSlaveOf(this)) return;
8162
8163          if(master != value)
8164          {
8165             if(master)
8166             {
8167                OldLink slaveHolder;
8168                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8169                   if(slaveHolder.data == this)
8170                   {
8171                      master.slaves.Delete(slaveHolder);
8172                      break;
8173                   }
8174             }
8175
8176             if(value)
8177             {
8178                value.slaves.Add(OldLink { data = this });
8179
8180                if(hotKey)
8181                {
8182                   if(master)
8183                      master.hotKeys.Remove(hotKey);
8184                   value.hotKeys.Add(hotKey);
8185                   hotKey = null;
8186                }
8187                if(master && master.defaultControl == this)
8188                   master.defaultControl = null;
8189
8190                if(style.isDefault && !value.defaultControl)
8191                   value.defaultControl = this;
8192             }
8193          }
8194          master = value;
8195       }
8196       get { return master ? master : parent; }
8197    };
8198
8199    property const char * caption
8200    {
8201       property_category $"Appearance"
8202       watchable
8203       set
8204       {
8205          delete caption;
8206          if(value)
8207          {
8208             caption = new char[strlen(value)+1];
8209             if(caption)
8210                strcpy(caption, value);
8211          }
8212          if(created)
8213             UpdateCaption();
8214       }
8215       get { return caption; }
8216    };
8217
8218    property Key hotKey
8219    {
8220       property_category $"Behavior"
8221       set
8222       {
8223          setHotKey = value;
8224          if(created)
8225          {
8226             if(value)
8227             {
8228                if(!hotKey)
8229                   master.hotKeys.Add(hotKey = HotKeySlot { });
8230                if(hotKey)
8231                {
8232                   hotKey.key = value;
8233                   hotKey.window = this;
8234                }
8235             }
8236             else if(hotKey)
8237             {
8238                master.hotKeys.Delete(hotKey);
8239                hotKey = null;
8240             }
8241          }
8242       }
8243       get { return hotKey ? hotKey.key : 0; }
8244    };
8245
8246    property Color background
8247    {
8248       property_category $"Appearance"
8249       set
8250       {
8251          background.color = value;
8252          firewatchers;
8253          if(created)
8254          {
8255             Update(null);
8256             if(this == rootWindow)
8257                guiApp.interfaceDriver.SetRootWindowColor(this);
8258          }
8259       }
8260       get { return background.color; }
8261    };
8262
8263    property Percentage opacity
8264    {
8265       property_category $"Appearance"
8266       set
8267       {
8268          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8269          drawBehind = (background.a == 255) ? false : true;
8270       }
8271       get { return background.a / 255.0f; }
8272    };
8273
8274    property Color foreground
8275    {
8276       property_category $"Appearance"
8277       set
8278       {
8279          foreground = value;
8280          firewatchers;
8281          if(created)
8282             Update(null);
8283       }
8284       get { return foreground; }
8285    };
8286
8287    property BorderStyle borderStyle
8288    {
8289       property_category $"Appearance"
8290       set
8291       {
8292          if(!((BorderBits)value).fixed)
8293          {
8294             style.hasClose = false;
8295             style.hasMaximize = false;
8296             style.hasMinimize = false;
8297             nativeDecorations = false;
8298          }
8299          style.borderBits = value;
8300          if(created)
8301          {
8302             int x, y, w, h;
8303             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8304
8305             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8306             Position(x, y, w, h, true, true, true, true, false, true);
8307             CreateSystemChildren();
8308          }
8309       }
8310       get { return (BorderStyle)style.borderBits; }
8311    };
8312
8313    property Size minClientSize
8314    {
8315       property_category $"Layout"
8316       set { minSize = value; }
8317       get { value = minSize; }
8318    };
8319
8320    property Size maxClientSize
8321    {
8322       property_category $"Layout"
8323       set { maxSize = value; }
8324       get { value = maxSize; }
8325    };
8326
8327    property bool hasMaximize
8328    {
8329       property_category $"Window Style"
8330       set
8331       {
8332          style.hasMaximize = value;
8333          if(value) { style.fixed = true; style.contour = true; }
8334          if(created)
8335          {
8336             int x, y, w, h;
8337             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8338
8339             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8340             Position(x, y, w, h, true, true, true, true, false, true);
8341
8342             CreateSystemChildren();
8343          }
8344       }
8345       get { return style.hasMaximize; }
8346    };
8347
8348    property bool hasMinimize
8349    {
8350       property_category $"Window Style"
8351       set
8352       {
8353          style.hasMinimize = value;
8354          if(value) { style.fixed = true; style.contour = true; }
8355          if(created)
8356          {
8357             int x, y, w, h;
8358             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8359
8360             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8361             Position(x, y, w, h, true, true, true, true, false, true);
8362
8363             CreateSystemChildren();
8364          }
8365       }
8366       get { return style.hasMinimize;  }
8367    };
8368
8369    property bool hasClose
8370    {
8371       property_category $"Window Style"
8372       set
8373       {
8374          style.hasClose = value;
8375          if(value) { style.fixed = true; style.contour = true; }
8376          if(created)
8377          {
8378             int x, y, w, h;
8379             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8380             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8381             Position(x, y, w, h, true, true, true, true, false, true);
8382             CreateSystemChildren();
8383          }
8384       }
8385       get { return style.hasClose; }
8386    };
8387
8388    property bool nonClient
8389    {
8390       property_category $"Layout"
8391       set
8392       {
8393          style.nonClient = value;
8394          if(value)
8395             style.stayOnTop = true;
8396       }
8397       get { return style.nonClient; }
8398    };
8399
8400    property bool inactive
8401    {
8402       property_category $"Behavior"
8403       set
8404       {
8405          if(value)
8406          {
8407             // *** NEW HERE: ***
8408             if(!style.inactive)
8409             {
8410                if(cycle)
8411                   parent.childrenCycle.Delete(cycle);
8412                if(order)
8413                   parent.childrenOrder.Delete(order);
8414                cycle = null;
8415                order = null;
8416             }
8417
8418             if(created)
8419             {
8420                active = false; // true;
8421                if(parent.activeChild == this)
8422                   parent.activeChild = null;
8423                if(parent.activeClient == this)
8424                   parent.activeClient = null;
8425             }
8426          }
8427          else
8428          {
8429             if(style.inactive)
8430             {
8431                if(!style.noCycle)
8432                {
8433                   parent.childrenCycle.Insert(
8434                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8435                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8436                      null,
8437                      cycle = OldLink { data = this });
8438                }
8439                parent.childrenOrder.Insert(
8440                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8441                   order = OldLink { data = this });
8442             }
8443          }
8444          style.inactive = value;
8445       }
8446       get { return style.inactive; }
8447    };
8448
8449    property bool clickThrough
8450    {
8451       property_category $"Behavior"
8452       set { style.clickThrough = value; }
8453       get { return style.clickThrough; }
8454    };
8455
8456    property bool isRemote
8457    {
8458       property_category $"Behavior"
8459       set { style.isRemote = value; }
8460       get { return style.isRemote; }
8461    };
8462
8463    property bool noCycle
8464    {
8465       property_category $"Behavior"
8466       set { style.noCycle = value; }
8467       get { return style.noCycle; }
8468    };
8469
8470    property bool isModal
8471    {
8472       property_category $"Behavior"
8473       set { style.modal = value; }
8474       get { return style.modal; }
8475    };
8476
8477    property bool interim
8478    {
8479       property_category $"Behavior"
8480       set { style.interim = value; }
8481       get { return style.interim; }
8482    };
8483
8484    property bool tabCycle
8485    {
8486       property_category $"Behavior"
8487       set { style.tabCycle = value; }
8488       get { return style.tabCycle; }
8489    };
8490
8491    property bool isDefault
8492    {
8493       property_category $"Behavior"
8494       set
8495       {
8496          if(master)
8497          {
8498             if(value)
8499             {
8500                /*Window sibling;
8501                for(sibling = parent.children.first; sibling; sibling = sibling.next)
8502                   if(sibling != this && sibling.style.isDefault)
8503                      sibling.style.isDefault = false;*/
8504                if(master.defaultControl)
8505                   master.defaultControl.style.isDefault = false;
8506                master.defaultControl = this;
8507             }
8508             else if(master.defaultControl == this)
8509                master.defaultControl = null;
8510
8511             // Update(null);
8512          }
8513          style.isDefault = value;
8514          if(created)
8515             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8516       }
8517       get { return style.isDefault; }
8518    };
8519
8520    property bool drawBehind
8521    {
8522       property_category $"Window Style"
8523       set { style.drawBehind = value; }
8524       get { return style.drawBehind; }
8525    };
8526
8527    property bool hasMenuBar
8528    {
8529       property_category $"Window Style"
8530       set
8531       {
8532          if(value)
8533          {
8534             if(!menu)
8535             {
8536                menu = Menu { };
8537                incref menu;
8538             }
8539             if(created && !menuBar)
8540             {
8541                menuBar =
8542                   PopupMenu
8543                   {
8544                      this, menu = menu,
8545                      isMenuBar = true,
8546                      anchor = Anchor { top = 23, left = 1, right = 1 },
8547                      size.h = 24,
8548                      inactive = true, nonClient = true
8549                   };
8550                menuBar.Create();
8551             }
8552          }
8553          else if(created && menuBar)
8554          {
8555             menuBar.Destroy(0);
8556             menuBar = null;
8557          }
8558          style.hasMenuBar = value;
8559       }
8560       get { return style.hasMenuBar; }
8561    };
8562
8563    property bool hasStatusBar
8564    {
8565       property_category $"Window Style"
8566       set
8567       {
8568          if(value)
8569          {
8570             if(!statusBar)
8571             {
8572                statusBar = StatusBar { this };
8573                incref statusBar;
8574                if(created)
8575                   statusBar.Create();
8576             }
8577          }
8578          else if(statusBar)
8579             delete statusBar;
8580          style.hasStatusBar = value;
8581       }
8582       get { return style.hasStatusBar; }
8583    };
8584    property bool stayOnTop
8585    {
8586       property_category $"Window Style"
8587       set
8588       {
8589          if(value)
8590          {
8591             if(created && !style.stayOnTop)
8592             {
8593                if(rootWindow == this)
8594                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8595                else if(parent.children.last != this)
8596                {
8597                   parent.children.Move(this, parent.children.last);
8598                   Update(null);
8599                }
8600             }
8601             style.stayOnTop = true;
8602          }
8603          else
8604          {
8605             if(created && style.stayOnTop)
8606             {
8607                if(rootWindow == this)
8608                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8609                else
8610                {
8611                   Window last;
8612                   if(order)
8613                   {
8614                      OldLink order;
8615                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev;
8616                          order && ((Window)order.data).style.stayOnTop;
8617                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8618                       last = order ? order.data : null;
8619                   }
8620                   else
8621                   {
8622                      for(last = parent.children.last;
8623                          last && last.style.stayOnTop;
8624                          last = last.prev);
8625                   }
8626
8627                   parent.children.Move(this, last);
8628                   Update(null);
8629                }
8630             }
8631             style.stayOnTop = false;
8632          }
8633       }
8634       get { return style.stayOnTop; }
8635    };
8636
8637    property Menu menu
8638    {
8639       property_category $"Window Style"
8640       set
8641       {
8642          delete menu;
8643          if(value)
8644          {
8645             menu = value;
8646             incref menu;
8647          }
8648
8649          if(menuBar && !value)
8650          {
8651             menuBar.Destroy(0);
8652             menuBar = null;
8653          }
8654          if(created)
8655          {
8656             if(!menuBar && style.hasMenuBar && value)
8657             {
8658                menuBar = PopupMenu
8659                          {
8660                             this, menu = value, isMenuBar = true,
8661                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24,
8662                             inactive = true, nonClient = true
8663                          };
8664                 menuBar.Create();
8665             }
8666             UpdateActiveDocument(null);
8667          }
8668       }
8669       get { return menu; }
8670    };
8671
8672    property FontResource font
8673    {
8674       property_category $"Appearance"
8675       watchable
8676       isset { return setFont ? true : false; }
8677       set
8678       {
8679          if(this)
8680          {
8681             if(value && !setFont) { stopwatching(parent, font); }
8682             else if(!value && setFont)
8683             {
8684                watch(parent)
8685                {
8686                   font
8687                   {
8688                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8689                      firewatchers font;
8690                      Update(null);
8691                   }
8692                };
8693             }
8694
8695             if(setFont)
8696             {
8697                RemoveResource(setFont);
8698                delete setFont;
8699             }
8700             if(systemFont)
8701             {
8702                RemoveResource(systemFont);
8703                delete systemFont;
8704             }
8705             setFont = value;
8706             if(setFont)
8707             {
8708                incref setFont;
8709                AddResource(setFont);
8710             }
8711
8712             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8713             if(!usedFont)
8714             {
8715                systemFont = guiApp.currentSkin.SystemFont();
8716                incref systemFont;
8717                usedFont = systemFont;
8718                AddResource(systemFont);
8719             }
8720
8721             firewatchers;
8722
8723             Update(null);
8724          }
8725       }
8726       get { return usedFont; }
8727    };
8728
8729    property SizeAnchor sizeAnchor
8730    {
8731       property_category $"Layout"
8732       isset
8733       {
8734          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8735                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8736             sizeAnchor.isClientW != sizeAnchor.isClientH;
8737       }
8738       set
8739       {
8740          int x, y, w, h;
8741          sizeAnchor = value;
8742
8743          normalSizeAnchor = sizeAnchor;
8744
8745          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8746          {
8747             stateAnchor = normalAnchor;
8748             stateSizeAnchor = normalSizeAnchor;
8749
8750             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8751             Position(x,y, w, h, true, true, true, true, false, true);
8752          }
8753       }
8754       get
8755       {
8756          value =
8757          {
8758             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8759             sizeAnchor.isClientW,
8760             sizeAnchor.isClientH
8761          };
8762       }
8763    };
8764
8765    property Size size
8766    {
8767       property_category $"Layout"
8768       isset
8769       {
8770          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8771                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8772             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8773       }
8774       set
8775       {
8776          int x, y, w, h;
8777
8778          sizeAnchor.isClientW = false;
8779          sizeAnchor.isClientH = false;
8780          sizeAnchor.size = value;
8781
8782          normalSizeAnchor = sizeAnchor;
8783
8784          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8785          {
8786             stateAnchor = normalAnchor;
8787             stateSizeAnchor = normalSizeAnchor;
8788
8789             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8790             Position(x, y, w, h, true, true, true, true, false, true);
8791             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8792          }
8793       }
8794       get { value = size; }
8795    };
8796
8797    property Size clientSize
8798    {
8799       property_category $"Layout"
8800       isset
8801       {
8802          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8803                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8804             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8805       }
8806       set
8807       {
8808          int x, y, w, h;
8809          sizeAnchor.isClientW = true;
8810          sizeAnchor.isClientH = true;
8811          sizeAnchor.size = value;
8812
8813          normalSizeAnchor = sizeAnchor;
8814
8815          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8816          {
8817             stateAnchor = normalAnchor;
8818             stateSizeAnchor = normalSizeAnchor;
8819
8820             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8821             Position(x,y, w, h, true, true, true, true, false, true);
8822             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8823          }
8824       }
8825       get { value = this ? clientSize : { 0, 0 }; }
8826    };
8827
8828    property Size initSize { get { value = sizeAnchor.size; } };
8829
8830    property Anchor anchor
8831    {
8832       property_category $"Layout"
8833       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8834
8835       set
8836       {
8837          if(value != null)
8838          {
8839             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8840             {
8841                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8842                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8843             }
8844             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8845             {
8846                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8847                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8848             }
8849             anchor = value;
8850
8851             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type))
8852             {
8853                anchor.left.distance = 0;
8854                anchor.horz.type = 0;
8855             }
8856             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8857             {
8858                anchor.top.distance = 0;
8859                anchor.vert.type = 0;
8860             }
8861
8862             anchored = true;
8863
8864             //if(created)
8865             {
8866                int x, y, w, h;
8867
8868                normalAnchor = anchor;
8869
8870                // Break the anchors for moveable/resizable windows
8871                /*if(style.fixed ) //&& value.left.type == cascade)
8872                {
8873                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8874
8875                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8876                   normalSizeAnchor = SizeAnchor { { w, h } };
8877                   anchored = false;
8878                }*/
8879                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8880                {
8881                   stateAnchor = normalAnchor;
8882                   stateSizeAnchor = normalSizeAnchor;
8883
8884                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8885                   Position(x, y, w, h, true, true, true, true, false, true);
8886                }
8887             }
8888          }
8889          else
8890          {
8891             anchored = false;
8892          }
8893       }
8894       get { value = this ? anchor : Anchor { }; }
8895    };
8896
8897    property Point position
8898    {
8899       property_category $"Layout"
8900       set
8901       {
8902          if(value == null) return;
8903
8904          anchor.left = value.x;
8905          anchor.top  = value.y;
8906          anchor.right.type = none;
8907          anchor.bottom.type = none;
8908          //if(created)
8909          {
8910             int x, y, w, h;
8911
8912             normalAnchor = anchor;
8913
8914             // Break the anchors for moveable/resizable windows
8915             /*
8916             if(style.fixed)
8917             {
8918                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8919
8920                normalAnchor.left = x;
8921                normalAnchor.top = y;
8922                normalAnchor.right.type = none;
8923                normalAnchor.bottom.type = none;
8924                normalSizeAnchor.size.width = w;
8925                normalSizeAnchor.size.height = h;
8926                anchored = false;
8927             }
8928             */
8929             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8930             {
8931                stateAnchor = normalAnchor;
8932                stateSizeAnchor = normalSizeAnchor;
8933
8934                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8935                Position(x,y, w, h, true, true, true, true, false, true);
8936             }
8937          }
8938       }
8939       get { value = position; }
8940    };
8941
8942    property bool disabled
8943    {
8944       property_category $"Behavior"
8945       set
8946       {
8947          if(this && disabled != value)
8948          {
8949             disabled = value;
8950             if(created)
8951                Update(null);
8952          }
8953       }
8954       get { return (bool)disabled; }
8955    };
8956
8957    property bool isEnabled
8958    {
8959       get
8960       {
8961          Window parent;
8962          for(parent = this; parent; parent = parent.parent)
8963             if(parent.disabled)
8964                return false;
8965          return true;
8966       }
8967    };
8968
8969    property WindowState state
8970    {
8971       property_category $"Behavior"
8972       set { SetState(value, false, 0); }
8973       get { return this ? state : 0; }
8974    };
8975
8976    property bool visible
8977    {
8978       property_category $"Behavior"
8979       set
8980       {
8981          if(this && !value && !style.hidden && parent)
8982          {
8983             bool wasActiveChild = parent.activeChild == this;
8984             Window client = null;
8985
8986             style.hidden = true;
8987             if(style.isActiveClient)
8988             {
8989                parent.numPositions--;
8990                if(state == minimized) parent.numIcons--;
8991             }
8992
8993             if(created)
8994             {
8995                OldLink prevOrder = null;
8996
8997                if(rootWindow == this)
8998                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8999                else
9000                {
9001                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
9002                   if(style.nonClient)
9003                   {
9004                      box.left   -= parent.clientStart.x;
9005                      box.top    -= parent.clientStart.y;
9006                      box.right  -= parent.clientStart.x;
9007                      box.bottom -= parent.clientStart.y;
9008                   }
9009                   parent.Update(box);
9010                }
9011                if(_isModal && master && master.modalSlave == this)
9012                   master.modalSlave = null;
9013
9014                if(order)
9015                {
9016                   OldLink tmpPrev = order.prev;
9017                   client = tmpPrev ? tmpPrev.data : null;
9018                   if(client && !client.style.hidden && !client.destroyed && client.created)
9019                      prevOrder = tmpPrev;
9020                   for(;;)
9021                   {
9022                      client = tmpPrev ? tmpPrev.data : null;
9023                      if(client == this) { client = null; break; }
9024                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
9025                      {
9026                         tmpPrev = client.order.prev;
9027                      }
9028                      else
9029                      {
9030                         if(client)
9031                            prevOrder = tmpPrev;
9032                         break;
9033                      }
9034                   }
9035
9036                   // If this window can be an active client, make sure the next window we activate can also be one
9037                   if(!style.nonClient && style.isActiveClient)
9038                   {
9039                      tmpPrev = prevOrder;
9040                      for(;;)
9041                      {
9042                         client = tmpPrev ? tmpPrev.data : null;
9043                         if(client == this) { client = null; break; }
9044                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
9045                         {
9046                            tmpPrev = client.order.prev;
9047                         }
9048                         else
9049                         {
9050                            if(client)
9051                               prevOrder = tmpPrev;
9052                            break;
9053                         }
9054                      }
9055                      if(client && client.style.hidden) client = null;
9056                   }
9057                }
9058
9059                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
9060                {
9061                   if(order && prevOrder && prevOrder.data != this)
9062                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
9063                   else
9064                      ActivateEx(false, false, false, true, null, null);
9065
9066                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
9067                   if(parent.activeClient == this)
9068                   {
9069                      parent.activeClient = null;
9070                      parent.UpdateActiveDocument(null);
9071                   }
9072                }
9073                else if(parent.activeClient == this)
9074                {
9075                   parent.activeClient = client;
9076                   parent.UpdateActiveDocument(this);
9077                }
9078
9079                // *** Not doing this anymore ***
9080               /*
9081                if(cycle)
9082                   parent.childrenCycle.Delete(cycle);
9083                if(order)
9084                   parent.childrenOrder.Delete(order);
9085                cycle = null;
9086                order = null;
9087                */
9088
9089                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9090             }
9091
9092             firewatchers;
9093          }
9094          else if(this && value && style.hidden)
9095          {
9096             style.hidden = false;
9097             if(created)
9098             {
9099                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9100                if(rootWindow == this)
9101                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
9102
9103                if(_isModal && master)
9104                   master.modalSlave = this;
9105
9106                if(style.isActiveClient)
9107                {
9108                   positionID = parent.GetPositionID(this);
9109                   parent.numPositions++;
9110                   if(state == minimized) parent.numIcons++;
9111                }
9112
9113                // *** NOT DOING THIS ANYMORE ***
9114                /*
9115                if(!(style.inactive))
9116                {
9117                   if(!(style.noCycle))
9118                   {
9119                      cycle = parent.childrenCycle.AddAfter(
9120                         (parent.activeChild && parent.activeChild.cycle) ?
9121                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
9122                      cycle.data = this;
9123                   }
9124                   order = parent.childrenOrder.AddAfter(
9125                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
9126                      sizeof(OldLink));
9127                   order.data = this;
9128                }
9129                */
9130
9131                /*
9132                if(true || !parent.activeChild)
9133                   ActivateEx(true, false, true, true, null, null);
9134                */
9135                if(creationActivation == activate && guiApp.desktop.active)
9136                   ActivateEx(true, false, true, true, null, null);
9137                else if((creationActivation == activate || creationActivation == flash) && !object)
9138                {
9139                   MakeActive();
9140                   if(this == rootWindow)
9141                      Flash();
9142                }
9143
9144                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9145                Update(null);
9146
9147                // rootWindow.
9148                ConsequentialMouseMove(false);
9149             }
9150
9151             firewatchers;
9152          }
9153          else if(this)
9154             style.hidden = !value;
9155       }
9156
9157       get { return (style.hidden || !setVisible) ? false : true; }
9158    };
9159
9160    property bool isDocument
9161    {
9162       property_category $"Document"
9163       set { style.isDocument = value; if(value) SetupFileMonitor(); }
9164       get { return style.isDocument; }
9165    };
9166
9167    property bool mergeMenus
9168    {
9169       property_category $"Window Style"
9170       set { mergeMenus = value; }
9171       get { return (bool)mergeMenus; }
9172    };
9173
9174    property bool hasHorzScroll
9175    {
9176       property_category $"Window Style"
9177       set
9178       {
9179          if(value)
9180          {
9181             if(!style.hasHorzScroll && created)
9182             {
9183                CreateSystemChildren();
9184                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9185             }
9186          }
9187          else if(style.hasHorzScroll)
9188          {
9189             sbh.Destroy(0);
9190             sbh = null;
9191             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9192          }
9193          style.hasHorzScroll = value;
9194       }
9195
9196       get { return style.hasHorzScroll; }
9197    };
9198
9199    property bool hasVertScroll
9200    {
9201       property_category $"Window Style"
9202       set
9203       {
9204          if(value)
9205          {
9206             if(!style.hasVertScroll && created)
9207             {
9208                style.hasVertScroll = true;
9209                CreateSystemChildren();
9210                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9211             }
9212          }
9213          else if(style.hasVertScroll)
9214          {
9215             sbv.Destroy(0);
9216             sbv = null;
9217             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9218          }
9219          style.hasVertScroll = value;
9220       }
9221       get { return style.hasVertScroll; }
9222    };
9223
9224    property bool dontHideScroll
9225    {
9226       property_category $"Behavior"
9227       set
9228       {
9229          scrollFlags.dontHide = value;
9230          if(value)
9231          {
9232             //UpdateScrollBars(true, true);
9233             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9234          }
9235          else
9236          {
9237             // UpdateScrollBars(true, true);
9238             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9239          }
9240       }
9241       get { return scrollFlags.dontHide; }
9242    };
9243
9244    property bool dontScrollVert
9245    {
9246       property_category $"Behavior"
9247       set { style.dontScrollVert = value; }
9248       get { return style.dontScrollVert; }
9249    };
9250    property bool dontScrollHorz
9251    {
9252       property_category $"Behavior"
9253       set { style.dontScrollHorz = value; }
9254       get { return style.dontScrollHorz; }
9255    };
9256
9257    property bool snapVertScroll
9258    {
9259       property_category $"Behavior"
9260       set
9261       {
9262          scrollFlags.snapY = value;
9263          if(sbv) sbv.snap = value;
9264       }
9265       get { return scrollFlags.snapY; }
9266    };
9267    property bool snapHorzScroll
9268    {
9269        property_category $"Behavior"
9270       set
9271       {
9272          scrollFlags.snapX = value;
9273          if(sbh) sbh.snap = value;
9274       }
9275       get { return scrollFlags.snapX; }
9276    };
9277
9278    property Point scroll
9279    {
9280       property_category $"Behavior"
9281       set { if(this) SetScrollPosition(value.x, value.y); }
9282       get { value = scroll; }
9283    };
9284
9285    property bool modifyVirtualArea
9286    {
9287       property_category $"Behavior"
9288       set { modifyVirtArea = value; }
9289       get { return (bool)modifyVirtArea; }
9290    };
9291
9292    property bool dontAutoScrollArea
9293    {
9294       property_category $"Behavior"
9295       // Activating a child control out of view will automatically scroll to make it in view
9296       set { noAutoScrollArea = value; }
9297       get { return (bool)noAutoScrollArea; }
9298    };
9299
9300    property const char * fileName
9301    {
9302       property_category $"Document"
9303       set
9304       {
9305          SetupFileMonitor();
9306
9307          if(menu && ((!fileName && value) || (fileName && !value)))
9308          {
9309             MenuItem item = menu.FindItem(MenuFileSave, 0);
9310             if(item) item.disabled = !modifiedDocument && value;
9311          }
9312
9313          delete fileName;
9314
9315          if(value && value[0])
9316             fileName = CopyString(value);
9317
9318          if(parent && this == parent.activeClient)
9319             parent.UpdateActiveDocument(null);
9320          else
9321             UpdateCaption();
9322
9323          // if(style.isDocument)
9324          if(!saving)
9325             fileMonitor.fileName = value;
9326       }
9327       get { return fileName; }
9328    };
9329
9330    property int64 id
9331    {
9332       property_category $"Data"
9333       set { id = value; }
9334       get { return id; }
9335    };
9336
9337    property bool modifiedDocument
9338    {
9339       property_category $"Document"
9340       set
9341       {
9342          if(style.isDocument || fileName)
9343          {
9344             if(menu)
9345             {
9346                MenuItem item = menu.FindItem(MenuFileSave, 0);
9347                if(item) item.disabled = !value && fileName;
9348             }
9349          }
9350
9351          if(modifiedDocument != value)
9352          {
9353             modifiedDocument = value;
9354             if(style.isDocument || fileName)
9355                UpdateCaption();
9356          }
9357       }
9358       get { return (bool)modifiedDocument; }
9359    };
9360
9361    property bool showInTaskBar
9362    {
9363       property_category $"Window Style"
9364       set { style.showInTaskBar = value; }
9365       get { return style.showInTaskBar; }
9366    };
9367    property FileDialog saveDialog { set { saveDialog = value; } };
9368    property bool isActiveClient
9369    {
9370       property_category $"Behavior"
9371       set
9372       {
9373          if(parent && style.isActiveClient != value && !style.hidden)
9374          {
9375             if(value)
9376             {
9377                if(state == minimized) parent.numIcons++;
9378                parent.numPositions++;
9379             }
9380             else
9381             {
9382                if(state == minimized) parent.numIcons--;
9383                parent.numPositions--;
9384             }
9385          }
9386          style.isActiveClient = value;
9387       }
9388       get { return style.isActiveClient; }
9389    };
9390
9391    property Cursor cursor
9392    {
9393       property_category $"Appearance"
9394       set
9395       {
9396          cursor = value;
9397          SelectMouseCursor();
9398       }
9399       get { return cursor; }
9400    };
9401
9402 //#if !defined(ECERE_VANILLA)
9403    property const char * name
9404    {
9405       property_category $"Design"
9406       get
9407       {
9408          return (this && object) ? object.name : null;
9409       }
9410       set
9411       {
9412          if(activeDesigner)
9413             activeDesigner.RenameObject(object, value);
9414       }
9415    };
9416 //#endif
9417    property const char * displayDriver
9418    {
9419       property_category $"Behavior"
9420       set
9421       {
9422          dispDriver = GetDisplayDriver(value);
9423          //DisplayModeChanged();
9424       }
9425       get
9426       {
9427          return dispDriver ? dispDriver.name : null;
9428       }
9429    }
9430
9431    // RUNTIME PROPERTIES
9432    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9433    property Size scrollArea
9434    {
9435       property_category $"Behavior"
9436       set
9437       {
9438          if(value != null)
9439             SetScrollArea(value.w, value.h, false);
9440          else
9441             SetScrollArea(0,0, true);
9442       }
9443       get { value = scrollArea; }
9444       isset
9445       {
9446          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9447       }
9448    };
9449    property bool is3D
9450    {
9451       property_category $"Layout"
9452       set { if(this) is3D = value; }
9453       get { return (bool)is3D; }
9454    };
9455
9456    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9457
9458    // Will be merged with font later
9459    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9460    property Point clientStart { get { value = clientStart; } };
9461    property Point absPosition { get { value = absPosition; } };
9462    property Anchor normalAnchor { get { value = normalAnchor; } };
9463    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9464    property bool active { get { return (bool)active; } };
9465    property bool created { get { return (bool)created; } };
9466    property bool destroyed { get { return (bool)destroyed; } };
9467    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9468    property Window firstChild { get { return children.first; } };
9469    property Window lastChild { get { return children.last; } };
9470    property Window activeClient { get { return activeClient; } };
9471    property Window activeChild { get { return activeChild; } };
9472    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9473    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9474    property ScrollBar horzScroll { get { return sbh; } };
9475    property ScrollBar vertScroll { get { return sbv; } };
9476    property StatusBar statusBar { get { return statusBar; } };
9477    property Window rootWindow { get { return rootWindow; } };
9478    property bool closing { get { return (bool)closing; } set { closing = value; } };
9479    property int documentID { get { return documentID; } };
9480    property Window previous { get { return prev; } }
9481    property Window next { get { return next; } }
9482    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9483    property PopupMenu menuBar { get { return menuBar; } }
9484    property ScrollBar sbv { get { return sbv; } }
9485    property ScrollBar sbh { get { return sbh; } }
9486    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9487    property void * systemHandle { get { return windowHandle; } }
9488    property Button minimizeButton { get { return sysButtons[0]; } };
9489    property Button maximizeButton { get { return sysButtons[1]; } };
9490    property Button closeButton { get { return sysButtons[2]; } };
9491    property BitmapResource icon
9492    {
9493       get { return icon; }
9494       set
9495       {
9496          icon = value;
9497          if(icon) incref icon;
9498          if(created)
9499             guiApp.interfaceDriver.SetIcon(this, value);
9500       }
9501    };
9502    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9503    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9504    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9505    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9506    property bool nativeDecorations
9507    {
9508       get { return (bool)nativeDecorations; }
9509       set { nativeDecorations = value; }
9510 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9511       isset
9512       {
9513          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9514          bool result = false;
9515          if(nativeDecorations)
9516          {
9517             if(rootWindow == this)
9518                result = true;
9519             else
9520             {
9521                if(formDesigner && activeDesigner)
9522                {
9523                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9524                   Window form = cd ? cd.form : null;
9525                   if(form && parent == form.parent)
9526                      result = true;
9527                }
9528             }
9529          }
9530          return result != style.fixed;
9531       }
9532 #endif
9533    };
9534    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9535
9536    property const char * text
9537    {
9538       property_category $"Deprecated"
9539       watchable
9540       set { property::caption = value; }
9541       get { return property::caption; }
9542    }
9543 private:
9544    // Data
9545    //char * yo;
9546    Window prev, next;
9547    WindowBits style;       // Window Style
9548    char * caption;            // Name / Caption
9549    Window parent;    // Parent window
9550    OldList children;          // List of children in Z order
9551    Window activeChild;     // Child window having focus
9552    Window activeClient;
9553    Window previousActive;  // Child active prior to activating the default child
9554    Window master;          // Window owning and receiving notifications concerning this window
9555    OldList slaves;            // List of windows belonging to this window
9556    Display display;        // Display this window is drawn into
9557
9558    Point position;         // Position in parent window client area
9559    Point absPosition;      // Absolute position
9560    Point clientStart;      // Client area position from (0,0) in this window
9561    Size size;              // Size
9562    Size clientSize;        // Client area size
9563    Size scrollArea;        // Virtual Scroll area size
9564    Size reqScrollArea;     // Requested virtual area size
9565    Point scroll;           // Virtual area scrolling position
9566    ScrollBar sbh, sbv;        // Scrollbar window handles
9567    Cursor cursor;        // Mouse cursor used for this window
9568    WindowState state;
9569    PopupMenu menuBar;
9570    StatusBar statusBar;
9571    Button sysButtons[3];
9572    char * fileName;
9573    Box clientArea;         // Client Area box clipped to parent
9574    Key setHotKey;
9575    HotKeySlot hotKey;        // HotKey for this window
9576    int numDocuments;
9577    int numPositions;
9578    Menu menu;
9579    ScrollFlags scrollFlags;// Window Scrollbar Flags
9580    int64 id;                 // Control ID
9581    int documentID;
9582    ColorAlpha background;  // Background color used to draw the window area
9583    Color foreground;
9584    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9585    OldList childrenCycle;     // Cycling order
9586    OldLink cycle;             // Element of parent's cycling order
9587    OldList childrenOrder;     // Circular Z-Order
9588    OldLink order;             // Element of parent's circular Z-Order
9589    Window modalSlave;      // Slave window blocking this window's interaction
9590
9591    Window rootWindow;      // Topmost system managed window
9592    void * windowHandle;    // System window handle
9593
9594    DialogResult returnCode;// Return code for modal windows
9595
9596    Point sbStep;           // Scrollbar line scrolling steps
9597
9598    Anchor stateAnchor;
9599    SizeAnchor stateSizeAnchor;
9600
9601    Anchor normalAnchor;
9602    SizeAnchor normalSizeAnchor;
9603
9604    Size skinMinSize;       // Minimal window size based on style
9605    Point scrolledPos;      // Scrolled position
9606    Box box;                // Window box clipped to parent
9607    Box * against;          // What to clip the box to
9608
9609    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9610    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9611    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9612    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9613    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9614    Point scrolledArea;     // Distance to scroll area by
9615    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9616
9617    OldList hotKeys;           // List of the hotkeys of all children
9618    Window defaultControl;  // Default child control
9619    Size minSize;
9620    Size maxSize;
9621
9622    ColorAlpha * palette;   // Color palette used for this window
9623
9624    int caretSize;          // Size of caret, non zero if a caret is present
9625    Point caretPos;         // Caret position
9626
9627    void * systemParent;    // Parent System Window for embedded windows
9628
9629    int iconID;
9630    int numIcons;
9631    int positionID;
9632
9633    Mutex mutex;
9634    WindowState lastState;
9635
9636    FileMonitor fileMonitor;
9637
9638    FontResource setFont, systemFont;
9639    FontResource usedFont;
9640    FontResource captionFont;
9641    OldList resources;
9642    FileDialog saveDialog;
9643    Anchor anchor;
9644    SizeAnchor sizeAnchor;
9645
9646    // FormDesigner data
9647    ObjectInfo object;
9648    Window control;
9649    Extent * tempExtents; //[4];
9650    BitmapResource icon;
9651    void * windowData;
9652    CreationActivationOption creationActivation;
9653    struct
9654    {
9655       bool active:1;            // true if window and ancestors are active
9656       bool acquiredInput:1;     // true if the window is processing state based input
9657       bool modifiedDocument:1;
9658       bool disabled:1;          // true if window cannot interact
9659       bool isForegroundWindow:1;// true while a root window is being activated
9660       bool visible:1;           // Visibility flag
9661       bool destroyed:1;         // true if window is being destroyed
9662       bool anchored:1;          // true if this window is repositioned when the parent resizes
9663       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9664       bool mouseInside:1;
9665       bool positioned:1;
9666       bool created:1;
9667       bool is3D:1;
9668       bool mergeMenus:1;
9669       bool modifyVirtArea:1;
9670       bool noAutoScrollArea:1;
9671       bool closing:1;
9672       bool autoCreate:1;
9673       bool setVisible:1;      // FOR FORM DESIGNER
9674       bool wasCreated:1;
9675       bool fullRender:1;
9676       bool moveable:1;
9677       bool alphaBlend:1;
9678       bool composing:1;
9679       bool useSharedMemory:1;
9680       bool resized:1;
9681       bool saving:1;
9682       bool nativeDecorations:1;
9683       bool manageDisplay:1;
9684       bool formDesigner:1; // True if we this is running in the form editor
9685       bool requireRemaximize:1;
9686    };
9687
9688    // Checks used internally for them not to take effect in FormDesigner
9689    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9690    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9691
9692    WindowController controller;
9693    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9694 };
9695
9696 public class CommonControl : Window
9697 {
9698    // creationActivation = doNothing;
9699
9700    ToolTip toolTip;
9701    public property const String toolTip
9702    {
9703       property_category $"Appearance"
9704       set
9705       {
9706          if(created) CommonControl::OnDestroy();
9707          delete toolTip;
9708          toolTip = value ? ToolTip { tip = value; } : null;
9709          incref toolTip;
9710          if(created) CommonControl::OnCreate();
9711       }
9712       get { return toolTip ? toolTip.tip : null; }
9713    }
9714
9715    void OnDestroy()
9716    {
9717       if(toolTip)
9718          // (Very) Ugly work around for the fact that the parent watcher
9719          // won't fire when it's already been disconnected...
9720          eInstance_FireSelfWatchers(toolTip,
9721             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9722    }
9723
9724    bool OnCreate()
9725    {
9726       if(toolTip)
9727          toolTip.parent = this;
9728       return true;
9729    }
9730    ~CommonControl()
9731    {
9732       delete toolTip;
9733    }
9734 };
9735
9736 public class Percentage : float
9737 {
9738    const char * OnGetString(char * string, float * fieldData, bool * needClass)
9739    {
9740       int c;
9741       int last = 0;
9742       sprintf(string, "%.2f", this);
9743       c = strlen(string)-1;
9744       for( ; c >= 0; c--)
9745       {
9746          if(string[c] != '0')
9747             last = Max(last, c);
9748          if(string[c] == '.')
9749          {
9750             if(last == c)
9751                string[c] = 0;
9752             else
9753                string[last+1] = 0;
9754             break;
9755          }
9756       }
9757       return string;
9758    }
9759 };
9760
9761 public void ApplySkin(Class c, const char * name, void ** vTbl)
9762 {
9763    char className[1024];
9764    Class sc;
9765    OldLink d;
9766    int m;
9767
9768    subclass(Window) wc = (subclass(Window))c;
9769    subclass(Window) base = (subclass(Window))c.base;
9770
9771    sprintf(className, "%sSkin_%s", name, c.name);
9772    wc.pureVTbl = c._vTbl;
9773    c._vTbl = new void *[c.vTblSize];
9774    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9775    sc = eSystem_FindClass(c.module.application, className);
9776
9777    if(vTbl)
9778    {
9779       for(m = 0; m < c.base.vTblSize; m++)
9780       {
9781          if(c._vTbl[m] == base.pureVTbl[m])
9782             c._vTbl[m] = vTbl[m];
9783       }
9784    }
9785    if(sc)
9786    {
9787       for(m = 0; m < c.vTblSize; m++)
9788       {
9789          if(sc._vTbl[m] != wc.pureVTbl[m])
9790             c._vTbl[m] = sc._vTbl[m];
9791       }
9792    }
9793
9794    for(d = c.derivatives.first; d; d = d.next)
9795    {
9796       ApplySkin(d.data, name, c._vTbl);
9797    }
9798 }
9799
9800 public void UnapplySkin(Class c)
9801 {
9802    subclass(Window) wc = (subclass(Window))c;
9803    OldLink d;
9804
9805    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9806    {
9807       delete c._vTbl;
9808       c._vTbl = wc.pureVTbl;
9809       wc.pureVTbl = null;
9810    }
9811
9812    for(d = c.derivatives.first; d; d = d.next)
9813    {
9814       UnapplySkin(d.data);
9815    }
9816 }
9817 /*
9818 void CheckFontIntegrity(Window window)
9819 {
9820    Window c;
9821    if(window)
9822    {
9823       if(window.usedFont && window.usedFont.font == 0xecececec)
9824       {
9825          FontResource uf = window.usedFont;
9826          char * className = window._class.name;
9827          char * text = window.text;
9828          Print("");
9829       }
9830       for(c = window.firstChild; c; c = c.next)
9831          CheckFontIntegrity(c);
9832    }
9833 }*/
9834
9835 public class ControllableWindow : Window
9836 {
9837    /*WindowController controller;
9838    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9839    ~ControllableWindow() { delete controller; }*/
9840 }
9841
9842 class WindowControllerInterface : ControllableWindow
9843 {
9844    bool OnKeyDown(Key key, unichar ch)
9845    {
9846       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch);
9847       if(result)
9848          result = ((bool (*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown])(controller.window, key, ch);
9849       return result;
9850    }
9851
9852    bool OnKeyUp(Key key, unichar ch)
9853    {
9854       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch);
9855       if(result)
9856          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp])(controller.window, key, ch);
9857       return result;
9858    }
9859
9860    bool OnKeyHit(Key key, unichar ch)
9861    {
9862       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch);
9863       if(result)
9864          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit])(controller.window, key, ch);
9865       return result;
9866    }
9867
9868    bool OnMouseMove(int x, int y, Modifiers mods)
9869    {
9870       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods);
9871       if(result)
9872          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove])(controller.window, x, y, mods);
9873       return result;
9874    }
9875
9876    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9877    {
9878       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods);
9879       if(result)
9880          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown])(controller.window, x, y, mods);
9881       return result;
9882    }
9883
9884    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9885    {
9886       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods);
9887       if(result)
9888          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp])(controller.window, x, y, mods);
9889       return result;
9890    }
9891
9892    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9893    {
9894       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9895       if(result)
9896          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick])(controller.window, x, y, mods);
9897       return result;
9898    }
9899
9900    bool OnRightButtonDown(int x, int y, Modifiers mods)
9901    {
9902       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods);
9903       if(result)
9904          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown])(controller.window, x, y, mods);
9905       return result;
9906    }
9907
9908    bool OnRightButtonUp(int x, int y, Modifiers mods)
9909    {
9910       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods);
9911       if(result)
9912          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp])(controller.window, x, y, mods);
9913       return result;
9914    }
9915
9916    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9917    {
9918       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9919       if(result)
9920          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick])(controller.window, x, y, mods);
9921       return result;
9922    }
9923
9924    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9925    {
9926       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods);
9927       if(result)
9928          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown])(controller.window, x, y, mods);
9929       return result;
9930    }
9931
9932    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9933    {
9934       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods);
9935       if(result)
9936          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp])(controller.window, x, y, mods);
9937       return result;
9938    }
9939
9940    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9941    {
9942       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9943       if(result)
9944          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick])(controller.window, x, y, mods);
9945       return result;
9946    }
9947
9948    void OnResize(int width, int height)
9949    {
9950       ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
9951       ((void(*)(Window, int, int))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize])(controller.window, width, height);
9952    }
9953
9954    void OnRedraw(Surface surface)
9955    {
9956       ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
9957       ((void(*)(Window, Surface))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(controller.window, surface);
9958    }
9959
9960    bool OnCreate()
9961    {
9962       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller);
9963       if(result)
9964          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate])(controller.window);
9965       return result;
9966    }
9967
9968    bool OnLoadGraphics()
9969    {
9970       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller);
9971       if(result)
9972          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics])(controller.window);
9973       return result;
9974    }
9975
9976    void OnUnloadGraphics()
9977    {
9978       ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
9979       ((void(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics])(controller.window);
9980    }
9981 }
9982
9983 public class WindowController<class V>
9984 {
9985 public:
9986    property Window window
9987    {
9988       set
9989       {
9990          uint size = class(Window).vTblSize;
9991          if(value)
9992          {
9993             windowVTbl = new void *[size];
9994             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9995             if(value._vTbl == value._class._vTbl)
9996             {
9997                value._vTbl = new void *[value._class.vTblSize];
9998                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9999             }
10000             {
10001                int c;
10002                for(c = 0; c < size; c++)
10003                {
10004                   void * function = class(WindowControllerInterface)._vTbl[c];
10005                   if(function != DefaultFunction)
10006                      value._vTbl[c] = function;
10007                   else
10008                      value._vTbl[c] = windowVTbl[c];
10009                }
10010             }
10011          }
10012          else
10013             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
10014          window = value;
10015       }
10016       get { return window; }
10017    }
10018    property V controlled
10019    {
10020       set { controlled = value; }
10021       get { return controlled; }
10022    }
10023    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
10024    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
10025    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
10026    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
10027    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
10028    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
10029    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10030    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
10031    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
10032    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10033    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
10034    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
10035    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10036    virtual void V::OnResize(WindowController controller, int width, int height);
10037    virtual void V::OnRedraw(WindowController controller, Surface surface);
10038    virtual bool V::OnCreate(WindowController controller);
10039    virtual bool V::OnLoadGraphics(WindowController controller);
10040    virtual void V::OnUnloadGraphics(WindowController controller);
10041
10042 private:
10043    int (** windowVTbl)();
10044    V controlled;
10045    Window window;
10046
10047    ~WindowController()
10048    {
10049       delete windowVTbl;
10050    }
10051 }