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