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