4b4fdec0175bb3f167a3910536c984992f6d2722
[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(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)
6362                            ActivateEx(true, false, true, true, null, null);
6363                         else if(creationActivation == flash)
6364                            Flash();
6365                      }
6366
6367                      if(!destroyed)
6368                         rootWindow.ConsequentialMouseMove(false);
6369
6370                      result = true;
6371                   }
6372                }
6373             }
6374          }
6375          /*
6376          if(!result)
6377          {
6378             Destroy(0);
6379             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6380          }
6381          */
6382
6383          if(!result)
6384          {
6385             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6386             created = false;
6387             //style.hidden = true; // !visible;
6388             style.hidden = !visible;
6389             if(master.modalSlave == this)
6390                master.modalSlave = null;
6391          }
6392          delete this;
6393       }
6394       return result;
6395    }
6396
6397    void WriteCaption(Surface surface, int x, int y)
6398    {
6399       if(caption)
6400          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6401    }
6402
6403    void Update(Box region)
6404    {
6405       if(this)
6406       {
6407          Window rootWindow;
6408
6409          rootWindow = this.rootWindow;
6410
6411          // rootWindow.mutex.Wait();
6412          if(!destroyed && visible && display)
6413          {
6414             Window child;
6415             Box realBox;
6416
6417             // Testing this to avoid repetitve full update to take time...
6418             if(dirtyArea.count == 1)
6419             {
6420                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6421                if(item.box.left <= box.left &&
6422                   item.box.top <= box.top &&
6423                   item.box.right >= box.right &&
6424                   item.box.bottom >= box.bottom)
6425                {
6426                   rootWindow.dirty = true;
6427                   return;
6428                }
6429             }
6430
6431             if(display.flags.flipping && !rootWindow.dirty)
6432             {
6433                if(this == rootWindow)
6434                   region = null;
6435                else
6436                {
6437                   rootWindow.Update(null);
6438                   return;
6439                }
6440             }
6441
6442             rootWindow.dirty = true;
6443
6444             if(region != null)
6445             {
6446                realBox = region;
6447                realBox.left += clientStart.x;
6448                realBox.top += clientStart.y;
6449                realBox.right += clientStart.x;
6450                realBox.bottom += clientStart.y;
6451                realBox.Clip(box);
6452             }
6453             else
6454                realBox = box;
6455
6456             if(realBox.right >= realBox.left &&
6457                realBox.bottom >= realBox.top)
6458             {
6459                // if(!rootWindow.fullRender)
6460                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6461
6462                for(child = children.first; child; child = child.next)
6463                {
6464                   if(!child.is3D)
6465                   {
6466                      Box box = realBox;
6467                      box.left -= child.absPosition.x - absPosition.x;
6468                      box.top -= child.absPosition.y - absPosition.y;
6469                      box.right -= child.absPosition.x - absPosition.x;
6470                      box.bottom -= child.absPosition.y - absPosition.y;
6471                      if(box.right >= child.box.left && box.left <= child.box.right &&
6472                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6473                      {
6474                         box.left -= child.clientStart.x;
6475                         box.top -= child.clientStart.y;
6476                         box.right -= child.clientStart.x;
6477                         box.bottom -= child.clientStart.y;
6478                         child.Update(box);
6479                      }
6480                   }
6481                }
6482
6483                realBox.left += absPosition.x - rootWindow.absPosition.x;
6484                realBox.top += absPosition.y - rootWindow.absPosition.y;
6485                realBox.right += absPosition.x - rootWindow.absPosition.x;
6486                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6487                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6488             }
6489          }
6490          else if(this == guiApp.desktop)
6491          {
6492             Window window;
6493             for(window = children.first; window; window = window.next)
6494             {
6495                if(!window.is3D)
6496                {
6497                   if(region != null)
6498                   {
6499                      Box childBox = region;
6500
6501                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6502                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6503                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6504                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6505
6506                      window.Update(childBox);
6507                   }
6508                   else
6509                      window.Update(null);
6510                }
6511             }
6512          }
6513
6514          // rootWindow.mutex.Release();
6515       }
6516    }
6517
6518    bool Capture(void)
6519    {
6520       bool result = true;
6521       if(guiApp.windowCaptured != this)
6522       {
6523          if(guiApp.windowCaptured)
6524             result = false;
6525          else
6526          {
6527             //Logf("Captured %s (%s)\n", caption, class.name);
6528             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6529             guiApp.windowCaptured = this;
6530          }
6531       }
6532       return result;
6533    }
6534
6535    bool Destroy(int64 code)
6536    {
6537       //if(created)
6538       if(this)
6539       {
6540          if(!destroyed && !CloseConfirmation(false)) return false;
6541          incref this;
6542          if(DestroyEx(code))
6543          {
6544             // TOCHECK: Should autoCreate be set to false here?
6545             autoCreate = false;
6546             wasCreated = false;
6547             delete this;
6548             return true;
6549          }
6550          delete this;
6551       }
6552       return false;
6553    }
6554
6555    void Move(int x, int y, int w, int h)
6556    {
6557       normalAnchor = Anchor { left = x, top = y };
6558       normalSizeAnchor = SizeAnchor { size = { w, h } };
6559
6560       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6561       {
6562          if(destroyed) return;
6563
6564          stateAnchor = normalAnchor;
6565          stateSizeAnchor = normalSizeAnchor;
6566
6567          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6568          Position(x,y, w, h, true, true, true, true, false, true);
6569       }
6570    }
6571
6572    DialogResult Modal(void)
6573    {
6574       isModal = true;
6575       if(Create())
6576          return DoModal();
6577
6578       // FIXES MEMORY LEAK IF Create() FAILED
6579       incref this;
6580       delete this;
6581       return 0;
6582    }
6583
6584    void SetScrollArea(int width, int height, bool snapToStep)
6585    {
6586       if(snapToStep)
6587       {
6588          int stepX = sbStep.x, stepY = sbStep.y;
6589          // Needed to make snapped down position match the skin's check of client area
6590          // against realvirtual
6591          if(guiApp.textMode)
6592          {
6593             SNAPDOWN(stepX, textCellW);
6594             SNAPDOWN(stepY, textCellH);
6595             stepX = Max(stepX, textCellW);
6596             stepY = Max(stepY, textCellH);
6597          }
6598          if(scrollFlags.snapX)
6599             SNAPUP(width, stepX);
6600          if(scrollFlags.snapY)
6601             SNAPUP(height, stepY);
6602       }
6603
6604       reqScrollArea.w = width;
6605       reqScrollArea.h = height;
6606       noAutoScrollArea = (width > 0 || height > 0);
6607
6608       UpdateScrollBars(true, true);
6609    }
6610
6611    void SetScrollPosition(int x, int y)
6612    {
6613       if(sbh)
6614          sbh.Action(setPosition, x, 0);
6615       else
6616       {
6617          int range;
6618          int seen = clientSize.w, total = reqScrollArea.w;
6619          seen = Max(1,seen);
6620          if(scrollFlags.snapX)
6621             SNAPDOWN(seen, sbStep.x);
6622
6623          if(!total) total = seen;
6624          range = total - seen + 1;
6625          range = Max(range, 1);
6626          if(x < 0) x = 0;
6627          if(x >= range) x = range - 1;
6628
6629          if(scrollFlags.snapX)
6630             SNAPUP(x, sbStep.x);
6631
6632          if(scroll.x != x)
6633             OnHScroll(setPosition, x, 0);
6634
6635          if(guiApp.textMode)
6636          {
6637             SNAPDOWN(x, textCellW);
6638          }
6639          scroll.x = x;
6640       }
6641
6642       if(sbv)
6643          sbv.Action(setPosition, y, 0);
6644       else
6645       {
6646          int range;
6647          int seen = clientSize.h, total = reqScrollArea.h;
6648          seen = Max(1,seen);
6649
6650          if(scrollFlags.snapY)
6651             SNAPDOWN(seen, sbStep.y);
6652
6653          if(!total) total = seen;
6654          range = total - seen + 1;
6655          range = Max(range, 1);
6656          if(y < 0) y = 0;
6657          if(y >= range) y = range - 1;
6658
6659          if(scrollFlags.snapY)
6660             SNAPUP(y, sbStep.y);
6661
6662          if(scroll.y != y)
6663             OnVScroll(setPosition, y, 0);
6664          if(guiApp.textMode)
6665          {
6666             SNAPDOWN(y, textCellH);
6667          }
6668          scroll.y = y;
6669       }
6670       if(!sbh || !sbv)
6671          UpdateCaret(false, false);
6672    }
6673
6674    void SetScrollLineStep(int stepX, int stepY)
6675    {
6676       sbStep.x = stepX;
6677       sbStep.y = stepY;
6678       if(guiApp.textMode)
6679       {
6680          SNAPDOWN(stepX, textCellW);
6681          SNAPDOWN(stepY, textCellH);
6682          stepX = Max(stepX, textCellW);
6683          stepY = Max(stepY, textCellH);
6684       }
6685       if(sbh)
6686          sbh.lineStep = stepX;
6687       if(sbv)
6688          sbv.lineStep = stepY;
6689    }
6690
6691    void SetState(WindowState newState, bool activate, Modifiers mods)
6692    {
6693       if(created)
6694       {
6695          if(state == newState || OnStateChange(newState, mods))
6696          {
6697             //WindowState prevState = state;
6698
6699             StopMoving();
6700
6701             // This used to be at the end of the brackets... moved for X, testing...
6702             // This has the effect of activating the window through the system...
6703             if(rootWindow == this)
6704                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6705
6706             SetStateEx(newState, activate);
6707
6708             if(rootWindow == this && !rootWindow.nativeDecorations)
6709             {
6710                int x = position.x, y = position.y;
6711                /*if(style.interim)
6712                {
6713                   x -= guiApp.desktop.absPosition.x;
6714                   y -= guiApp.desktop.absPosition.y;
6715                }*/
6716                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6717             }
6718
6719             //state = newState;
6720             //state = prevState;
6721
6722             if(state != maximized && style.hasMaximize)
6723             {
6724                Window child;
6725                for(child = parent.children.first; child; child = child.next)
6726                {
6727                   if(child != this && child.state == maximized)
6728                      child.SetStateEx(normal, false);
6729                }
6730             }
6731
6732             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6733                parent.UpdateScrollBars(true, true);
6734
6735             /*
6736             // Do we really need this stuff here?
6737             // Shouldn't the Activate stuff take care of it?
6738             if(parent.rootWindow == parent && style)
6739             {
6740                char caption[2048];
6741                parent.FigureCaption(caption);
6742                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6743                parent.UpdateDecorations();
6744             }
6745             */
6746
6747             rootWindow.ConsequentialMouseMove(false);
6748          }
6749       }
6750       else
6751          state = newState;
6752    }
6753
6754    BitmapResource GetIcon(SkinBitmap iconID)
6755    {
6756       return guiApp.currentSkin.GetBitmap(iconID);
6757    }
6758
6759    void SetMouseRange(Box range)
6760    {
6761       if(range || guiApp.fullScreenMode)
6762       {
6763          Box clip;
6764          if(range != null)
6765          {
6766             clip.left   = range.left + absPosition.x + clientStart.x;
6767             clip.top    = range.top + absPosition.y + clientStart.y;
6768             clip.right  = range.right + absPosition.x + clientStart.x;
6769             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6770          }
6771          else
6772          {
6773             clip.left   = guiApp.desktop.box.left;
6774             clip.top    = guiApp.desktop.box.top;
6775             clip.right  = guiApp.desktop.box.right;
6776             clip.bottom = guiApp.desktop.box.bottom;
6777          }
6778          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6779       }
6780       else
6781          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6782    }
6783
6784    void SetMouseRangeToClient(void)
6785    {
6786       if(guiApp.fullScreenMode || this != guiApp.desktop)
6787       {
6788          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6789          box.Clip(clientArea);
6790          SetMouseRange(box);
6791       }
6792       else
6793          SetMouseRange(null);
6794    }
6795
6796    void SetMouseRangeToWindow(void)
6797    {
6798       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6799       if(this == guiApp.desktop)
6800          SetMouseRangeToClient();
6801       else
6802          SetMouseRange(box);
6803    }
6804
6805    // x, y: Desktop Coordinates
6806    void ShowSysMenu(int x, int y)
6807    {
6808       Menu menu { };
6809       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6810       MenuItem
6811       {
6812          menu, $"Restore", r, NotifySelect = MenuWindowRestore,
6813          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6814       };
6815       MenuItem
6816       {
6817          menu, $"Move", m, NotifySelect = MenuWindowMove,
6818          disabled = !style.fixed || state == maximized
6819       };
6820       MenuItem
6821       {
6822          menu, $"Size", s, NotifySelect = MenuWindowSize,
6823          disabled = !style.sizable || state != normal
6824       };
6825       MenuItem
6826       {
6827          menu, $"Minimize", n, NotifySelect = MenuWindowMinimize,
6828          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6829       };
6830       MenuItem
6831       {
6832          menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize,
6833          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6834       };
6835       MenuItem
6836       {
6837          menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop,
6838          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6839       };
6840       MenuDivider { menu };
6841       MenuItem
6842       {
6843          menu, $"Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6844          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6845       };
6846       windowMenu.Create();
6847    }
6848
6849    void Activate(void)
6850    {
6851       ActivateEx(true, true, true, true, null, null);
6852    }
6853
6854    void MakeActive(void)
6855    {
6856       ActivateEx(true, false, true, false, null, null);
6857    }
6858
6859    void SoftActivate(void)
6860    {
6861       if(guiApp.desktop.active)
6862          Activate();
6863       else if(!active)
6864          Flash();
6865    }
6866
6867    void Deactivate(void)
6868    {
6869       ActivateEx(false, true, true, true, null, null);
6870    }
6871
6872    void Flash(void)
6873    {
6874       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6875    }
6876
6877    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6878    {
6879       bool result = false;
6880       if(activeChild && activeChild.cycle)
6881       {
6882          Window modalWindow, child = activeChild;
6883          if(!clientOnly /*&& parent.tabCycle*/)
6884          {
6885             Window next = child;
6886             while(true)
6887             {
6888                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6889                {
6890                   if(cycleParents)
6891                   {
6892                      if(parent && parent.CycleChildren(backward, false, true, true))
6893                         return true;
6894                      break;
6895                   }
6896                   else
6897                      return false;
6898                }
6899                if(backward)
6900                   next = next.cycle.prev.data;
6901                else
6902                   next = next.cycle.next.data;
6903                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6904                   break;
6905             }
6906          }
6907          /*
6908          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) &&
6909             parent.tabCycle && parent.CycleChildren(backward, false, false))
6910             return true;
6911          */
6912
6913          if(tabCycleOnly && !tabCycle) return false;
6914
6915          while(child)
6916          {
6917             while(true)
6918             {
6919                if(backward)
6920                   child = child.cycle.prev.data;
6921                else
6922                   child = child.cycle.next.data;
6923                if(child == child.parent.activeChild)
6924                   return result;
6925                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6926                   break;
6927             }
6928             modalWindow = child.FindModal();
6929             if(!modalWindow)
6930             {
6931                // Scroll the window to include the active control
6932                if(sbh && !child.style.dontScrollHorz)
6933                {
6934                   if(child.scrolledPos.x < 0)
6935                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6936                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6937                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6938                }
6939                if(sbv && !child.style.dontScrollVert)
6940                {
6941                   if(child.scrolledPos.y < 0)
6942                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6943                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6944                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6945                }
6946             }
6947             result = true;
6948             child = modalWindow ? modalWindow : child;
6949             child.ActivateEx(true, true, true, true, null, null);
6950             if(child.tabCycle && child.childrenCycle.first)
6951                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6952             else
6953                break;
6954          }
6955       }
6956       else
6957          return false;
6958
6959       ConsequentialMouseMove(false);
6960       return result;
6961    }
6962
6963    void AddResource(Resource resource)
6964    {
6965       if(resource)
6966       {
6967          ResPtr ptr { resource = resource };
6968          resources.Add(ptr);
6969          incref resource;
6970
6971          // Load Graphics here if window is created already
6972          if(/*created && */display)
6973          {
6974             display.Lock(false);
6975             if(!ptr.loaded)   // This check prevents a leak in case a watcher on 'font' calls AddResource (ListBox FontResource leak)
6976                ptr.loaded = display.displaySystem.LoadResource(resource);
6977             display.Unlock();
6978          }
6979          /*
6980          // Temporary hack to load font right away for listbox in dropbox ...
6981          else if(master && master.display)
6982          {
6983             master.display.Lock(false);
6984             master.display.displaySystem.LoadResource(resource);
6985             master.display.Unlock();
6986          }
6987          */
6988       }
6989    }
6990
6991    void RemoveResource(Resource resource)
6992    {
6993       if(resource)
6994       {
6995          ResPtr ptr;
6996          for(ptr = resources.first; ptr; ptr = ptr.next)
6997          {
6998             if(ptr.resource == resource)
6999                break;
7000          }
7001
7002          if(ptr)
7003          {
7004             // Unload Graphics here if window is created already
7005             if(/*created && */display)
7006             {
7007                if(ptr.loaded)
7008                {
7009                   display.Lock(false);
7010                   display.displaySystem.UnloadResource(resource, ptr.loaded);
7011                   display.Unlock();
7012                   ptr.loaded = null;
7013                }
7014             }
7015             delete resource;
7016             resources.Delete(ptr);
7017          }
7018       }
7019    }
7020
7021    void SetCaret(int x, int y, int size)
7022    {
7023       if(!destroyed)
7024       {
7025          caretPos.x = x;
7026          caretPos.y = y;
7027          caretSize = size;
7028          if(active && !style.interim && isEnabled)
7029          {
7030             if(visible || !guiApp.caretOwner)
7031                guiApp.caretOwner = size ? this : null;
7032             if(size)
7033                UpdateCaret(false, false);
7034             else
7035             {
7036                guiApp.interfaceDriver.SetCaret(0,0,0);
7037                UpdateCaret(false, true);
7038                guiApp.caretEnabled = false;
7039             }
7040          }
7041          else if(style.inactive && active)
7042          {
7043             guiApp.interfaceDriver.SetCaret(0,0,0);
7044             UpdateCaret(false, true);
7045             guiApp.caretEnabled = false;
7046          }
7047       }
7048    }
7049
7050    void Scroll(int x, int y)
7051    {
7052       bool opaque = !style.drawBehind || background.a;
7053       if(opaque && display && display.flags.scrolling)
7054       {
7055          Box box = clientArea;
7056          box.left += clientStart.x;
7057          box.top += clientStart.y;
7058          box.right += clientStart.x;
7059          box.bottom += clientStart.y;
7060
7061          //scrollExtent.Free(null);
7062          scrollExtent.AddBox(box);
7063          scrolledArea.x += x;
7064          scrolledArea.y += y;
7065
7066          //scrollExtent.Free();
7067          //scrollExtent.AddBox(clientArea);
7068          //scrollExtent.Offset(clientStart.x, clientStart.y);
7069          //scrolledArea.x = x;
7070          //scrolledArea.y = y;
7071       }
7072       else
7073          Update(clientArea);
7074
7075       if(rootWindow)
7076          rootWindow.dirty = true;
7077    }
7078
7079    void ReleaseCapture()
7080    {
7081       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
7082       {
7083          Window oldCaptured = guiApp.windowCaptured;
7084          guiApp.windowCaptured = null;
7085          guiApp.prevWindow = null;
7086          incref oldCaptured;
7087
7088          //guiApp.Log("Released Capture\n");
7089
7090          guiApp.interfaceDriver.SetMouseCapture(null);
7091
7092          //oldCaptured.OnMouseCaptureLost();
7093
7094          if(oldCaptured)
7095             oldCaptured.ConsequentialMouseMove(false);
7096          delete oldCaptured;
7097       }
7098    }
7099
7100    private void _SetCaption(const char * format, va_list args)
7101    {
7102       if(this)
7103       {
7104          delete caption;
7105          if(format)
7106          {
7107             char caption[MAX_F_STRING];
7108             vsnprintf(caption, sizeof(caption), format, args);
7109             caption[sizeof(caption)-1] = 0;
7110
7111             this.caption = CopyString(caption);
7112          }
7113          if(created)
7114             UpdateCaption();
7115
7116          firewatchers caption;
7117       }
7118    }
7119
7120    /*deprecated*/ void SetText(const char * format, ...)
7121    {
7122       va_list args;
7123       va_start(args, format);
7124       _SetCaption(format, args);
7125       va_end(args);
7126    }
7127
7128    void SetCaption(const char * format, ...)
7129    {
7130       va_list args;
7131       va_start(args, format);
7132       _SetCaption(format, args);
7133       va_end(args);
7134    }
7135
7136    bool Grab(Bitmap bitmap, Box box, bool decorations)
7137    {
7138       bool result = false;
7139       if(display || this == guiApp.desktop)
7140       {
7141          Box clip = {MININT, MININT, MAXINT, MAXINT};
7142
7143          if(box != null)
7144             clip = box;
7145
7146          if(!decorations)
7147             clip.Clip(clientArea);
7148          else
7149             clip.Clip(this.box);
7150
7151          if(rootWindow != this)
7152          {
7153             clip.left   += absPosition.y;
7154             clip.top    += absPosition.y;
7155             clip.right  += absPosition.x;
7156             clip.bottom += absPosition.y;
7157          }
7158
7159          clip.left += decorations ? 0 : clientStart.x;
7160          clip.top += decorations ? 0 : clientStart.y;
7161          clip.right += decorations ? 0 : clientStart.x;
7162          clip.bottom += decorations ? 0 : clientStart.y;
7163
7164          if(display && display.flags.flipping)
7165          {
7166             rootWindow.Update(null);
7167             rootWindow.UpdateDisplay();
7168          }
7169
7170          if(!display)
7171          {
7172             Window window { };
7173             window.Create();
7174             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top,
7175                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7176             delete window;
7177          }
7178          else
7179             result = display.Grab(bitmap, clip.left, clip.top,
7180                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7181
7182          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7183          {
7184             if(!bitmap.Convert(null, pixelFormat888, null))
7185                result = false;
7186          }
7187       }
7188       return result;
7189    }
7190
7191    void GetMousePosition(int * x, int * y)
7192    {
7193       int mouseX = 0, mouseY = 0;
7194       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7195       {
7196          if(guiApp.driver)
7197             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7198          if(this != guiApp.desktop)
7199          {
7200             mouseX -= absPosition.x + clientStart.x;
7201             mouseY -= absPosition.y + clientStart.y;
7202          }
7203       }
7204       if(x) *x = mouseX;
7205       if(y) *y = mouseY;
7206    }
7207
7208    DialogResult DoModal()
7209    {
7210       DialogResult returnCode = 0;
7211       int terminated = terminateX;
7212       isModal = true;
7213       incref this;
7214       while(!destroyed && guiApp.driver != null)
7215       {
7216          if(terminateX != terminated)
7217          {
7218             terminated = terminateX;
7219             guiApp.desktop.Destroy(0);
7220             if(guiApp.desktop.created)
7221             {
7222                terminated = 0;
7223                //printf("Resetting terminate X to 0\n");
7224                terminateX = 0;
7225             }
7226             break;
7227          }
7228
7229          guiApp.UpdateDisplay();
7230          if(!guiApp.ProcessInput(false))
7231             guiApp.Wait();
7232       }
7233       returnCode = this.returnCode;
7234       delete this;
7235       return returnCode;
7236    }
7237
7238    void DoModalStart()
7239    {
7240       isModal = true;
7241       incref this;
7242    }
7243
7244    bool DoModalLoop()
7245    {
7246       return !destroyed && guiApp.driver != null && terminateX < 2;
7247    }
7248
7249    DialogResult DoModalEnd()
7250    {
7251       DialogResult returnCode = this.returnCode;
7252       delete this;
7253       return returnCode;
7254    }
7255
7256    // --- Window manipulation ---
7257    /*bool GetDisabled()
7258    {
7259       bool disabled = this.disabled;
7260       Window window;
7261       for(window = this; (window = window.master); )
7262       {
7263          if(window.disabled)
7264          {
7265             disabled = true;
7266             break;
7267          }
7268       }
7269       return disabled;
7270    }*/
7271
7272    // --- Mouse Manipulation ---
7273    void GetNCMousePosition(int * x, int * y)
7274    {
7275       GetMousePosition(x, y);
7276       if(x) *x += clientStart.x;
7277       if(y) *y += clientStart.y;
7278    }
7279
7280    // --- Carets manipulation ---
7281    void GetCaretPosition(Point caretPos)
7282    {
7283       caretPos = this.caretPos;
7284    }
7285
7286    int GetCaretSize(void)
7287    {
7288       return caretSize;
7289    }
7290
7291    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7292    {
7293       Destroy(button.id);
7294       return true;
7295    }
7296
7297    bool CloseConfirmation(bool parentClosing)
7298    {
7299       bool result = true;
7300       OldLink slave;
7301       Window child;
7302
7303       if(closing)
7304          return false;
7305       if(terminateX > 1)
7306          return true;
7307
7308       closing = true;
7309
7310       if(!OnClose(parentClosing))
7311          result = false;
7312
7313       // If you want to skip this, simply set modifiedDocument to false in OnClose
7314       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7315       {
7316          DialogResult dialogRes;
7317          char message[1024];
7318          if(fileName)
7319             sprintf(message, $"Save changes to %s?", fileName);
7320          else
7321             sprintf(message, $"Save changes to Untitled %d?", documentID);
7322
7323          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7324
7325          if(dialogRes == yes)
7326          {
7327             // TOFIX: Precomp error if brackets are taken out
7328             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7329          }
7330          else if(dialogRes == cancel)
7331             result = false;
7332       }
7333
7334       if(result)
7335       {
7336          for(slave = slaves.first; slave; slave = slave.next)
7337          {
7338             Window w = slave.data;
7339             if(w.parent != this && !w.IsDescendantOf(this) && !w.CloseConfirmation(true))
7340             {
7341                result = false;
7342                break;
7343             }
7344          }
7345       }
7346
7347       // Confirm closure of active clients first (We use OnClose() to hide instead of destroy in the IDE)
7348       if(result)
7349       {
7350          for(child = children.first; child; child = child.next)
7351             if(child.isActiveClient && !child.CloseConfirmation(true))
7352             {
7353                result = false;
7354                break;
7355             }
7356       }
7357       if(result)
7358       {
7359          for(child = children.first; child; child = child.next)
7360             if(!child.isActiveClient && !child.CloseConfirmation(true))
7361             {
7362                result = false;
7363                break;
7364             }
7365       }
7366       closing = false;
7367       return result;
7368    }
7369
7370    // Static methods... move them somewhere else?
7371    void ::RestoreCaret()
7372    {
7373       if(guiApp.caretOwner)
7374          guiApp.caretOwner.UpdateCaret(false, false);
7375    }
7376
7377    void ::FreeMouseRange()
7378    {
7379       guiApp.interfaceDriver.SetMouseRange(null, null);
7380    }
7381
7382    // Menu Methods
7383    bool MenuFileClose(MenuItem selection, Modifiers mods)
7384    {
7385       Window document = activeChild;
7386       if(document)
7387          document.Destroy(0);
7388       return true;
7389    }
7390
7391    bool MenuFileExit(MenuItem selection, Modifiers mods)
7392    {
7393       Destroy(0);
7394       return true;
7395    }
7396
7397    bool MenuFileSave(MenuItem selection, Modifiers mods)
7398    {
7399       SetupFileMonitor();
7400       if(fileName)
7401       {
7402          fileMonitor.fileName = null;
7403          saving = true;
7404
7405          if(OnSaveFile(fileName))
7406          {
7407             //if(OnFileModified != Window::OnFileModified)
7408             {
7409                saving = false;
7410                fileMonitor.fileName = fileName;
7411             }
7412             return true;
7413          }
7414          else
7415          {
7416             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7417             DialogResult answer = dialog.Modal();
7418             saving = false;
7419             if(answer != yes) return (bool)answer;
7420          }
7421       }
7422       return MenuFileSaveAs(selection, mods);
7423    }
7424
7425    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7426    {
7427       DialogResult result = (DialogResult)bool::true;
7428       FileDialog fileDialog = saveDialog;
7429
7430       SetupFileMonitor();
7431
7432       if(!fileDialog)
7433          fileDialog = FileDialog {};
7434       if(fileDialog)
7435       {
7436          incref fileDialog;
7437          if(fileName)
7438             fileDialog.filePath = fileName;
7439          else
7440          {
7441             char filePath[MAX_FILENAME];
7442             sprintf(filePath, "Untitled %d", documentID);
7443             fileDialog.filePath = filePath;
7444          }
7445          fileMonitor.fileName = null;
7446
7447          fileDialog.type = save;
7448          fileDialog.text = $"Save As";
7449
7450          while(true)
7451          {
7452             fileDialog.master = master.parent ? master : this;
7453             if(fileDialog.Modal() == ok)
7454             {
7455                const char * filePath = fileDialog.filePath;
7456                saving = true;
7457                if(OnSaveFile(filePath))
7458                {
7459                   saving = false;
7460                   property::fileName = filePath;
7461                   NotifySaved(master, this, filePath);
7462                   break;
7463                }
7464                else
7465                {
7466                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7467                   DialogResult answer = dialog.Modal();
7468                   saving = false;
7469                   if(answer != yes)
7470                   {
7471                      result = answer;
7472                      break;
7473                   }
7474                }
7475             }
7476             else
7477             {
7478                result = cancel;
7479                break;
7480             }
7481          }
7482          //if(OnFileModified != Window::OnFileModified && fileName)
7483          {
7484             if(fileName)
7485                fileMonitor.fileName = fileName;
7486          }
7487          delete fileDialog;
7488       }
7489       return (bool)result; // Actually returning result from Yes/NoCancel message box
7490    }
7491
7492    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7493    {
7494       Window document = activeChild;
7495       Window next;
7496       for(document = children.first; document; document = next)
7497       {
7498          next = document.next;
7499          if(document.style.isDocument || document.fileName)
7500             document.MenuFileSave(selection, mods);
7501       }
7502       return true;
7503    }
7504
7505    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7506    {
7507       Window document;
7508
7509       for(document = children.first; document; document = document.next)
7510          //if(document.style.isDocument && document.state == minimized)
7511          if(document.style.isActiveClient && document.state == minimized)
7512             document.SetState(minimized, false, mods);
7513       return true;
7514    }
7515
7516    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7517    {
7518       Window document = activeChild;
7519       if(document)
7520       {
7521          Window firstDocument = null;
7522          Window child;
7523          OldLink cycle = document.cycle.prev;
7524          int id = 0;
7525          while(true)
7526          {
7527             child = cycle.data;
7528             if(child.style.isActiveClient && !child.style.hidden)
7529             {
7530                Window last;
7531
7532                firstDocument = child;
7533                if(child.state == minimized)
7534                   child.SetState(minimized, false, mods);
7535                else
7536                {
7537                   child.positionID = id++;
7538                   child.SetState(normal, false, mods);
7539                   child.anchor.left.type = cascade;
7540                   {
7541                      int x, y, w, h;
7542                      child.normalSizeAnchor = *&child.sizeAnchor;
7543                      child.normalAnchor = child.anchor;
7544
7545                      // Break the anchors for moveable/resizable windows
7546                      if(child.style.fixed)
7547                      {
7548                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7549
7550                         (*&child.normalAnchor).left = x;
7551                         (*&child.normalAnchor).top = y;
7552                         (*&child.normalAnchor).right.type = none;
7553                         (*&child.normalAnchor).bottom.type = none;
7554
7555                         child.normalSizeAnchor.isClientW = false;
7556                         child.normalSizeAnchor.isClientH = false;
7557                         child.normalSizeAnchor.size.w = w;
7558                         child.normalSizeAnchor.size.h = h;
7559                         child.anchored = false;
7560                      }
7561
7562                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7563                      {
7564                         child.stateAnchor = child.normalAnchor;
7565                         child.stateSizeAnchor = child.normalSizeAnchor;
7566
7567                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7568                         child.Position(x, y, w, h, true, true, true, true, false, false);
7569                      }
7570                   }
7571                }
7572
7573                last = children.last;
7574                if(!child.style.stayOnTop)
7575                   for(; last && last.style.stayOnTop; last = last.prev);
7576                children.Move(child, last);
7577                childrenOrder.Move(child.order, childrenOrder.last);
7578             }
7579             if(cycle == document.cycle) break;
7580             cycle = cycle.prev;
7581          }
7582          if(firstDocument)
7583             firstDocument.Activate();
7584       }
7585       return true;
7586    }
7587
7588    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7589    {
7590       if(style.hasClose)
7591          Destroy(0);
7592       return true;
7593    }
7594
7595    // Close all closes all active clients, not all documents
7596    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7597    {
7598       Window next, document;
7599
7600       for(document = children.first; document; document = next)
7601       {
7602          for(next = document.next; next && !next.style.isActiveClient; next = next.next);
7603          if(document.style.isActiveClient)
7604             if(!document.Destroy(0) && !document.style.hidden)
7605                return false;
7606       }
7607       return true;
7608    }
7609
7610    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7611    {
7612       if(style.hasMaximize && state != maximized)
7613          SetState(maximized, 0, 0);
7614       return true;
7615    }
7616
7617    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7618    {
7619       if(style.hasMinimize && state != minimized)
7620       {
7621          SetState(minimized, 0, 0);
7622          parent.CycleChildren(false, true, false, true);
7623       }
7624       return true;
7625    }
7626
7627    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7628    {
7629       MenuMoveOrSize(false, selection ? true : false);
7630       return true;
7631    }
7632
7633    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7634    {
7635       CycleChildren(false, true, false, true);
7636       return true;
7637    }
7638
7639    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7640    {
7641       CycleChildren(true, true, false, true);
7642       return true;
7643    }
7644
7645    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7646    {
7647       MenuMoveOrSize(true, true);
7648       return true;
7649    }
7650
7651    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7652    {
7653       if(state != normal)
7654          SetState(normal, 0, 0);
7655       return true;
7656    }
7657
7658    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7659    {
7660       Window document;
7661       int64 id = selection.id;
7662       OldLink cycle = activeClient.cycle;
7663       int c = 0;
7664       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7665       while(true)
7666       {
7667          Window sibling = cycle.data;
7668          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7669          {
7670             if(c == id)
7671                break;
7672             c++;
7673          }
7674          cycle = cycle.next;
7675       }
7676       document = cycle.data;
7677       document.Activate();
7678
7679       //if(activeChild.state == maximized)
7680       //  document.SetState(maximized, false, mods);
7681       //else if(document.state == minimized)
7682       //   document.SetState(normal, false, mods);
7683       return true;
7684    }
7685
7686    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7687    {
7688       stayOnTop = !style.stayOnTop;
7689       return true;
7690    }
7691
7692    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7693    {
7694       Window document = activeChild;
7695       if(document)
7696       {
7697          Window firstDocument = null;
7698          OldLink cycle = document.cycle;
7699          int id = 0;
7700          while(true)
7701          {
7702             Window child = cycle.data;
7703             if(child.style.isActiveClient && !child.style.hidden)
7704             {
7705                if(!firstDocument) firstDocument = child;
7706                if(child.state == minimized)
7707                   child.SetState(minimized, false, mods);
7708                else
7709                {
7710                   child.positionID = id++;
7711                   child.SetState(normal, false, mods);
7712                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7713
7714                   child.anchor.left.type = hTiled;
7715                   {
7716                      int x, y, w, h;
7717                      child.normalSizeAnchor = *&child.sizeAnchor;
7718                      child.normalAnchor = child.anchor;
7719
7720                      // Break the anchors for moveable/resizable windows
7721                      if(child.style.fixed)
7722                      {
7723                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7724
7725                         (*&child.normalAnchor).left = x;
7726                         (*&child.normalAnchor).top = y;
7727                         (*&child.normalAnchor).right.type = none;
7728                         (*&child.normalAnchor).bottom.type = none;
7729                         child.normalSizeAnchor.isClientW = false;
7730                         child.normalSizeAnchor.isClientH = false;
7731                         child.normalSizeAnchor.size.w = w;
7732                         child.normalSizeAnchor.size.h = h;
7733                         child.anchored = false;
7734                      }
7735
7736                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7737                      {
7738                         child.stateAnchor = child.normalAnchor;
7739                         child.stateSizeAnchor = child.normalSizeAnchor;
7740
7741                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7742                         child.Position(x,y, w, h, true, true, true, true, false, true);
7743                      }
7744                   }
7745                }
7746             }
7747             if((cycle = cycle.next) == document.cycle) break;
7748          }
7749          if(firstDocument)
7750             firstDocument.Activate();
7751       }
7752       return true;
7753    }
7754
7755    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7756    {
7757       Window document = activeChild;
7758       if(document)
7759       {
7760          Window firstDocument = null;
7761          Window child;
7762          OldLink cycle = document.cycle;
7763          int id = 0;
7764          while(true)
7765          {
7766             child = cycle.data;
7767             //if(child.style.isDocument)
7768             if(child.style.isActiveClient && !child.style.hidden)
7769             {
7770                if(!firstDocument) firstDocument = child;
7771                if(child.state == minimized)
7772                   child.SetState(minimized, false, mods);
7773                else
7774                {
7775                   child.positionID = id++;
7776                   child.SetState(normal, false, mods);
7777                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7778
7779                   child.anchor.left.type = vTiled;
7780                   {
7781                      int x, y, w, h;
7782                      child.normalSizeAnchor = *&child.sizeAnchor;
7783                      child.normalAnchor = child.anchor;
7784
7785                      // Break the anchors for moveable/resizable windows
7786                      if(child.style.fixed)
7787                      {
7788                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7789
7790                         (*&child.normalAnchor).left = x;
7791                         (*&child.normalAnchor).top = y;
7792                         (*&child.normalAnchor).right.type = none;
7793                         (*&child.normalAnchor).bottom.type = none;
7794                         child.normalSizeAnchor.isClientW = false;
7795                         child.normalSizeAnchor.isClientH = false;
7796                         child.normalSizeAnchor.size.w = w;
7797                         child.normalSizeAnchor.size.h = h;
7798                         child.anchored = false;
7799                      }
7800
7801                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7802                      {
7803                         child.stateAnchor = child.normalAnchor;
7804                         child.stateSizeAnchor = child.normalSizeAnchor;
7805
7806                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7807                         child.Position(x,y, w, h, true, true, true, true, false, true);
7808                      }
7809                   }
7810                }
7811             }
7812             if((cycle = cycle.next) == document.cycle) break;
7813          }
7814          if(firstDocument)
7815             firstDocument.Activate();
7816       }
7817       return true;
7818    }
7819
7820    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7821    {
7822       WindowList dialog { master = this };
7823       Window document = (Window)(intptr)dialog.Modal();
7824       if(document)
7825       {
7826          if(activeChild.state == maximized)
7827             document.SetState(maximized, false, mods);
7828          else if(document.state == minimized)
7829             document.SetState(normal, false, mods);
7830          document.Activate();
7831       }
7832       return true;
7833    }
7834
7835    // Virtual Methods
7836    virtual bool OnCreate(void);
7837    virtual void OnDestroy(void);
7838    virtual void OnDestroyed(void);
7839    virtual bool OnClose(bool parentClosing);
7840    virtual bool OnStateChange(WindowState state, Modifiers mods);
7841    virtual bool OnPostCreate(void);
7842    virtual bool OnMoving(int *x, int *y, int w, int h);
7843    virtual bool OnResizing(int *width, int *height);
7844    virtual void OnResize(int width, int height);
7845    virtual void OnPosition(int x, int y, int width, int height);
7846    virtual bool OnLoadGraphics(void);
7847    virtual void OnApplyGraphics(void);
7848    virtual void OnUnloadGraphics(void);
7849    virtual void OnRedraw(Surface surface);
7850    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7851    virtual void OnActivateClient(Window client, Window previous);
7852    virtual bool OnKeyDown(Key key, unichar ch);
7853    virtual bool OnKeyUp(Key key, unichar ch);
7854    virtual bool OnKeyHit(Key key, unichar ch);
7855    virtual bool OnSysKeyDown(Key key, unichar ch);
7856    virtual bool OnSysKeyUp(Key key, unichar ch);
7857    virtual bool OnSysKeyHit(Key key, unichar ch);
7858    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7859    virtual bool OnMouseLeave(Modifiers mods);
7860    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7861    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7862    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7863    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7864    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7865    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7866    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7867    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7868    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7869    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7870    virtual void OnMouseCaptureLost(void);
7871    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7872    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7873    virtual void OnDrawOverChildren(Surface surface);
7874    virtual bool OnFileModified(FileChange fileChange, const char * param);
7875    virtual bool OnSaveFile(const char * fileName);
7876
7877    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
7878    // Note: A 'client' would refer to isActiveClient, rather than
7879    // being confined to the 'client area' (nonClient == false)
7880    virtual void OnChildAddedOrRemoved(Window child, bool removed);
7881    virtual void OnChildVisibilityToggled(Window child, bool visible);
7882    virtual void OnChildResized(Window child, int x, int y, int w, int h);
7883
7884    // Skins Virtual Functions
7885    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7886    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7887    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7888    {
7889       *cw = *w;
7890       *ch = *h;
7891    }
7892    virtual void ShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
7893    virtual void PreShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
7894    virtual bool IsMouseMoving(int x, int y, int w, int h)
7895    {
7896       return false;
7897    }
7898    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
7899    {
7900       return false;
7901    }
7902    virtual void UpdateNonClient();
7903    virtual void SetBox(Box box);    // This is used in the MySkin skin
7904    virtual bool IsInside(int x, int y)
7905    {
7906       return box.IsPointInside({x, y});
7907    }
7908    virtual bool IsOpaque()
7909    {
7910       return (!style.drawBehind || background.a == 255);
7911    }
7912
7913    // Notifications
7914    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7915    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7916    virtual void Window::NotifySaved(Window window, const char * filePath);
7917
7918    // Public Methods
7919
7920    // Properties
7921    property Window parent
7922    {
7923       property_category $"Layout"
7924       set
7925       {
7926          if(value || guiApp.desktop)
7927          {
7928             Window last;
7929             Window oldParent = parent;
7930             Anchor anchor = this.anchor;
7931
7932             if(value && value.IsDescendantOf(this)) return;
7933             if(value && value == this)
7934                return;
7935             if(!value) value = guiApp.desktop;
7936
7937             if(value == oldParent) return;
7938
7939             if(!master || (master == this.parent && master == guiApp.desktop))
7940                property::master = value;
7941
7942             if(parent)
7943             {
7944                parent.children.Remove(this);
7945
7946                parent.Update(
7947                {
7948                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7949                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7950                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7951                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7952                });
7953             }
7954
7955             last = value.children.last;
7956
7957             if(style.isDocument)
7958             {
7959                if(parent)
7960                   parent.numDocuments--;
7961                documentID = value.GetDocumentID();
7962             }
7963
7964             if(style.isActiveClient && !style.hidden)
7965             {
7966                if(parent && parent != guiApp.desktop && !(style.hidden))
7967                {
7968                   if(state == minimized) parent.numIcons--;
7969                   parent.numPositions--;
7970                }
7971             }
7972
7973             if(!style.stayOnTop)
7974                for(; last && last.style.stayOnTop; last = last.prev);
7975
7976             value.children.Insert(last, this);
7977
7978             // *** NEW HERE: ***
7979             if(cycle)
7980                parent.childrenCycle.Delete(cycle);
7981             if(order)
7982                parent.childrenOrder.Delete(order);
7983             cycle = null;
7984             order = null;
7985             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
7986             //           Should something else be done?
7987             if(parent && parent.activeChild == this)
7988                parent.activeChild = null;
7989             if(parent && parent.activeClient == this)
7990                parent.activeClient = null;
7991
7992             //if(created)
7993             {
7994                if(created)
7995                {
7996                   int x = position.x, y = position.y, w = size.w, h = size.h;
7997
7998                   int vpw, vph;
7999
8000                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
8001                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
8002
8003                   vpw = value.clientSize.w;
8004                   vph = value.clientSize.h;
8005                   if(style.nonClient)
8006                   {
8007                      vpw = value.size.w;
8008                      vph = value.size.h;
8009                   }
8010                   else if(style.fixed)
8011                   {
8012                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
8013                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
8014                   }
8015
8016                   anchor = this.anchor;
8017
8018                   if(anchor.left.type == offset)            anchor.left.distance = x;
8019                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
8020                   if(anchor.top.type == offset)             anchor.top.distance = y;
8021                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
8022                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
8023                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
8024                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
8025                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
8026                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
8027                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
8028
8029                   if(!anchor.left.type && !anchor.right.type)
8030                   {
8031                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
8032                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
8033                   }
8034                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
8035                   if(!anchor.top.type && !anchor.bottom.type)
8036                   {
8037                      anchor.vert.distance = (y + h / 2) - (vph / 2);
8038                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
8039                   }
8040                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
8041                }
8042                parent = value;
8043                parent.OnChildAddedOrRemoved(this, false);
8044
8045                // *** NEW HERE ***
8046                if(!style.inactive)
8047                {
8048                   if(!style.noCycle)
8049                      parent.childrenCycle.Insert(
8050                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8051                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8052                         null,
8053                         cycle = OldLink { data = this });
8054                   parent.childrenOrder.Insert(
8055                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8056                      order = OldLink { data = this });
8057                }
8058
8059                if(!style.hidden && style.isActiveClient)
8060                {
8061                   positionID = parent.GetPositionID(this);
8062                   parent.numPositions++;
8063                   if(state == minimized) parent.numIcons--;
8064                }
8065
8066                // *** FONT INHERITANCE ***
8067                if(!setFont && oldParent)
8068                   stopwatching(oldParent, font);
8069
8070                if(systemFont)
8071                {
8072                   RemoveResource(systemFont);
8073                   delete systemFont;
8074                }
8075                // TESTING WITH WATCHERS:
8076                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8077                // usedFont = setFont ? setFont : (systemFont);
8078
8079                if(!usedFont)
8080                {
8081                   if(guiApp.currentSkin)
8082                   {
8083                      systemFont = guiApp.currentSkin.SystemFont();
8084                      incref systemFont;
8085                   }
8086                   usedFont = systemFont;
8087                   AddResource(systemFont);
8088                }
8089
8090                if(!setFont)
8091                   watch(value)
8092                   {
8093                      font
8094                      {
8095                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8096                         firewatchers font;
8097                         Update(null);
8098                      }
8099                   };
8100
8101                firewatchers font;
8102
8103
8104                if(value.rootWindow && value.rootWindow.display && rootWindow)
8105                {
8106                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) ||
8107                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
8108
8109                   if(reloadGraphics)
8110                      UnloadGraphics(false);
8111                   if(created)
8112                      SetupDisplay();
8113                   if(reloadGraphics)
8114                      LoadGraphics(false, false);
8115
8116                   /*
8117                   if(value.rootWindow != rootWindow)
8118                      DisplayModeChanged();
8119                   else
8120                   */
8121                }
8122                scrolledPos.x = MININT; // Prevent parent update
8123                {
8124                   bool anchored = this.anchored;
8125                   property::anchor = anchor;
8126                   this.anchored = anchored;
8127                }
8128                /*
8129                {
8130                   int x, y, w, h;
8131                   if(guiApp.currentSkin)
8132                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
8133
8134                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8135                   Position(x, y, w, h, true, true, true, true, false, true);
8136                }
8137                */
8138
8139             }
8140             // else parent = value;
8141             if(oldParent)
8142                oldParent.OnChildAddedOrRemoved(this, true);
8143          }
8144       }
8145       get { return parent; }
8146    };
8147
8148    property Window master
8149    {
8150       property_category $"Behavior"
8151       set
8152       {
8153          //if(this == value) return;
8154          if(value && value.IsSlaveOf(this)) return;
8155
8156          if(master != value)
8157          {
8158             if(master)
8159             {
8160                OldLink slaveHolder;
8161                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8162                   if(slaveHolder.data == this)
8163                   {
8164                      master.slaves.Delete(slaveHolder);
8165                      break;
8166                   }
8167             }
8168
8169             if(value)
8170             {
8171                value.slaves.Add(OldLink { data = this });
8172
8173                if(hotKey)
8174                {
8175                   if(master)
8176                      master.hotKeys.Remove(hotKey);
8177                   value.hotKeys.Add(hotKey);
8178                   hotKey = null;
8179                }
8180                if(master && master.defaultControl == this)
8181                   master.defaultControl = null;
8182
8183                if(style.isDefault && !value.defaultControl)
8184                   value.defaultControl = this;
8185             }
8186          }
8187          master = value;
8188       }
8189       get { return master ? master : parent; }
8190    };
8191
8192    property const char * caption
8193    {
8194       property_category $"Appearance"
8195       watchable
8196       set
8197       {
8198          delete caption;
8199          if(value)
8200          {
8201             caption = new char[strlen(value)+1];
8202             if(caption)
8203                strcpy(caption, value);
8204          }
8205          if(created)
8206             UpdateCaption();
8207       }
8208       get { return caption; }
8209    };
8210
8211    property Key hotKey
8212    {
8213       property_category $"Behavior"
8214       set
8215       {
8216          setHotKey = value;
8217          if(created)
8218          {
8219             if(value)
8220             {
8221                if(!hotKey)
8222                   master.hotKeys.Add(hotKey = HotKeySlot { });
8223                if(hotKey)
8224                {
8225                   hotKey.key = value;
8226                   hotKey.window = this;
8227                }
8228             }
8229             else if(hotKey)
8230             {
8231                master.hotKeys.Delete(hotKey);
8232                hotKey = null;
8233             }
8234          }
8235       }
8236       get { return hotKey ? hotKey.key : 0; }
8237    };
8238
8239    property Color background
8240    {
8241       property_category $"Appearance"
8242       set
8243       {
8244          background.color = value;
8245          firewatchers;
8246          if(created)
8247          {
8248             Update(null);
8249             if(this == rootWindow)
8250                guiApp.interfaceDriver.SetRootWindowColor(this);
8251          }
8252       }
8253       get { return background.color; }
8254    };
8255
8256    property Percentage opacity
8257    {
8258       property_category $"Appearance"
8259       set
8260       {
8261          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8262          drawBehind = (background.a == 255) ? false : true;
8263       }
8264       get { return background.a / 255.0f; }
8265    };
8266
8267    property Color foreground
8268    {
8269       property_category $"Appearance"
8270       set
8271       {
8272          foreground = value;
8273          firewatchers;
8274          if(created)
8275             Update(null);
8276       }
8277       get { return foreground; }
8278    };
8279
8280    property BorderStyle borderStyle
8281    {
8282       property_category $"Appearance"
8283       set
8284       {
8285          if(!((BorderBits)value).fixed)
8286          {
8287             style.hasClose = false;
8288             style.hasMaximize = false;
8289             style.hasMinimize = false;
8290             nativeDecorations = false;
8291          }
8292          style.borderBits = value;
8293          if(created)
8294          {
8295             int x, y, w, h;
8296             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8297
8298             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8299             Position(x, y, w, h, true, true, true, true, false, true);
8300             CreateSystemChildren();
8301          }
8302       }
8303       get { return (BorderStyle)style.borderBits; }
8304    };
8305
8306    property Size minClientSize
8307    {
8308       property_category $"Layout"
8309       set { minSize = value; }
8310       get { value = minSize; }
8311    };
8312
8313    property Size maxClientSize
8314    {
8315       property_category $"Layout"
8316       set { maxSize = value; }
8317       get { value = maxSize; }
8318    };
8319
8320    property bool hasMaximize
8321    {
8322       property_category $"Window Style"
8323       set
8324       {
8325          style.hasMaximize = value;
8326          if(value) { style.fixed = true; style.contour = true; }
8327          if(created)
8328          {
8329             int x, y, w, h;
8330             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8331
8332             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8333             Position(x, y, w, h, true, true, true, true, false, true);
8334
8335             CreateSystemChildren();
8336          }
8337       }
8338       get { return style.hasMaximize; }
8339    };
8340
8341    property bool hasMinimize
8342    {
8343       property_category $"Window Style"
8344       set
8345       {
8346          style.hasMinimize = value;
8347          if(value) { style.fixed = true; style.contour = true; }
8348          if(created)
8349          {
8350             int x, y, w, h;
8351             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8352
8353             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8354             Position(x, y, w, h, true, true, true, true, false, true);
8355
8356             CreateSystemChildren();
8357          }
8358       }
8359       get { return style.hasMinimize;  }
8360    };
8361
8362    property bool hasClose
8363    {
8364       property_category $"Window Style"
8365       set
8366       {
8367          style.hasClose = value;
8368          if(value) { style.fixed = true; style.contour = true; }
8369          if(created)
8370          {
8371             int x, y, w, h;
8372             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8373             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8374             Position(x, y, w, h, true, true, true, true, false, true);
8375             CreateSystemChildren();
8376          }
8377       }
8378       get { return style.hasClose; }
8379    };
8380
8381    property bool nonClient
8382    {
8383       property_category $"Layout"
8384       set
8385       {
8386          style.nonClient = value;
8387          if(value)
8388             style.stayOnTop = true;
8389       }
8390       get { return style.nonClient; }
8391    };
8392
8393    property bool inactive
8394    {
8395       property_category $"Behavior"
8396       set
8397       {
8398          if(value)
8399          {
8400             // *** NEW HERE: ***
8401             if(!style.inactive)
8402             {
8403                if(cycle)
8404                   parent.childrenCycle.Delete(cycle);
8405                if(order)
8406                   parent.childrenOrder.Delete(order);
8407                cycle = null;
8408                order = null;
8409             }
8410
8411             if(created)
8412             {
8413                active = false; // true;
8414                if(parent.activeChild == this)
8415                   parent.activeChild = null;
8416                if(parent.activeClient == this)
8417                   parent.activeClient = null;
8418             }
8419          }
8420          else
8421          {
8422             if(style.inactive)
8423             {
8424                if(!style.noCycle)
8425                {
8426                   parent.childrenCycle.Insert(
8427                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8428                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8429                      null,
8430                      cycle = OldLink { data = this });
8431                }
8432                parent.childrenOrder.Insert(
8433                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8434                   order = OldLink { data = this });
8435             }
8436          }
8437          style.inactive = value;
8438       }
8439       get { return style.inactive; }
8440    };
8441
8442    property bool clickThrough
8443    {
8444       property_category $"Behavior"
8445       set { style.clickThrough = value; }
8446       get { return style.clickThrough; }
8447    };
8448
8449    property bool isRemote
8450    {
8451       property_category $"Behavior"
8452       set { style.isRemote = value; }
8453       get { return style.isRemote; }
8454    };
8455
8456    property bool noCycle
8457    {
8458       property_category $"Behavior"
8459       set { style.noCycle = value; }
8460       get { return style.noCycle; }
8461    };
8462
8463    property bool isModal
8464    {
8465       property_category $"Behavior"
8466       set { style.modal = value; }
8467       get { return style.modal; }
8468    };
8469
8470    property bool interim
8471    {
8472       property_category $"Behavior"
8473       set { style.interim = value; }
8474       get { return style.interim; }
8475    };
8476
8477    property bool tabCycle
8478    {
8479       property_category $"Behavior"
8480       set { style.tabCycle = value; }
8481       get { return style.tabCycle; }
8482    };
8483
8484    property bool isDefault
8485    {
8486       property_category $"Behavior"
8487       set
8488       {
8489          if(master)
8490          {
8491             if(value)
8492             {
8493                /*Window sibling;
8494                for(sibling = parent.children.first; sibling; sibling = sibling.next)
8495                   if(sibling != this && sibling.style.isDefault)
8496                      sibling.style.isDefault = false;*/
8497                if(master.defaultControl)
8498                   master.defaultControl.style.isDefault = false;
8499                master.defaultControl = this;
8500             }
8501             else if(master.defaultControl == this)
8502                master.defaultControl = null;
8503
8504             // Update(null);
8505          }
8506          style.isDefault = value;
8507          if(created)
8508             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8509       }
8510       get { return style.isDefault; }
8511    };
8512
8513    property bool drawBehind
8514    {
8515       property_category $"Window Style"
8516       set { style.drawBehind = value; }
8517       get { return style.drawBehind; }
8518    };
8519
8520    property bool hasMenuBar
8521    {
8522       property_category $"Window Style"
8523       set
8524       {
8525          if(value)
8526          {
8527             if(!menu)
8528             {
8529                menu = Menu { };
8530                incref menu;
8531             }
8532             if(created && !menuBar)
8533             {
8534                menuBar =
8535                   PopupMenu
8536                   {
8537                      this, menu = menu,
8538                      isMenuBar = true,
8539                      anchor = Anchor { top = 23, left = 1, right = 1 },
8540                      size.h = 24,
8541                      inactive = true, nonClient = true
8542                   };
8543                menuBar.Create();
8544             }
8545          }
8546          else if(created && menuBar)
8547          {
8548             menuBar.Destroy(0);
8549             menuBar = null;
8550          }
8551          style.hasMenuBar = value;
8552       }
8553       get { return style.hasMenuBar; }
8554    };
8555
8556    property bool hasStatusBar
8557    {
8558       property_category $"Window Style"
8559       set
8560       {
8561          if(value)
8562          {
8563             if(!statusBar)
8564             {
8565                statusBar = StatusBar { this };
8566                incref statusBar;
8567                if(created)
8568                   statusBar.Create();
8569             }
8570          }
8571          else if(statusBar)
8572             delete statusBar;
8573          style.hasStatusBar = value;
8574       }
8575       get { return style.hasStatusBar; }
8576    };
8577    property bool stayOnTop
8578    {
8579       property_category $"Window Style"
8580       set
8581       {
8582          if(value)
8583          {
8584             if(created && !style.stayOnTop)
8585             {
8586                if(rootWindow == this)
8587                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8588                else if(parent.children.last != this)
8589                {
8590                   parent.children.Move(this, parent.children.last);
8591                   Update(null);
8592                }
8593             }
8594             style.stayOnTop = true;
8595          }
8596          else
8597          {
8598             if(created && style.stayOnTop)
8599             {
8600                if(rootWindow == this)
8601                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8602                else
8603                {
8604                   Window last;
8605                   if(order)
8606                   {
8607                      OldLink order;
8608                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev;
8609                          order && ((Window)order.data).style.stayOnTop;
8610                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8611                       last = order ? order.data : null;
8612                   }
8613                   else
8614                   {
8615                      for(last = parent.children.last;
8616                          last && last.style.stayOnTop;
8617                          last = last.prev);
8618                   }
8619
8620                   parent.children.Move(this, last);
8621                   Update(null);
8622                }
8623             }
8624             style.stayOnTop = false;
8625          }
8626       }
8627       get { return style.stayOnTop; }
8628    };
8629
8630    property Menu menu
8631    {
8632       property_category $"Window Style"
8633       set
8634       {
8635          delete menu;
8636          if(value)
8637          {
8638             menu = value;
8639             incref menu;
8640          }
8641
8642          if(menuBar && !value)
8643          {
8644             menuBar.Destroy(0);
8645             menuBar = null;
8646          }
8647          if(created)
8648          {
8649             if(!menuBar && style.hasMenuBar && value)
8650             {
8651                menuBar = PopupMenu
8652                          {
8653                             this, menu = value, isMenuBar = true,
8654                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24,
8655                             inactive = true, nonClient = true
8656                          };
8657                 menuBar.Create();
8658             }
8659             UpdateActiveDocument(null);
8660          }
8661       }
8662       get { return menu; }
8663    };
8664
8665    property FontResource font
8666    {
8667       property_category $"Appearance"
8668       watchable
8669       isset { return setFont ? true : false; }
8670       set
8671       {
8672          if(this)
8673          {
8674             if(value && !setFont) { stopwatching(parent, font); }
8675             else if(!value && setFont)
8676             {
8677                watch(parent)
8678                {
8679                   font
8680                   {
8681                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8682                      firewatchers font;
8683                      Update(null);
8684                   }
8685                };
8686             }
8687
8688             if(setFont)
8689             {
8690                RemoveResource(setFont);
8691                delete setFont;
8692             }
8693             if(systemFont)
8694             {
8695                RemoveResource(systemFont);
8696                delete systemFont;
8697             }
8698             setFont = value;
8699             if(setFont)
8700             {
8701                incref setFont;
8702                AddResource(setFont);
8703             }
8704
8705             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8706             if(!usedFont)
8707             {
8708                systemFont = guiApp.currentSkin.SystemFont();
8709                incref systemFont;
8710                usedFont = systemFont;
8711                AddResource(systemFont);
8712             }
8713
8714             firewatchers;
8715
8716             Update(null);
8717          }
8718       }
8719       get { return usedFont; }
8720    };
8721
8722    property SizeAnchor sizeAnchor
8723    {
8724       property_category $"Layout"
8725       isset
8726       {
8727          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8728                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8729             sizeAnchor.isClientW != sizeAnchor.isClientH;
8730       }
8731       set
8732       {
8733          int x, y, w, h;
8734          sizeAnchor = value;
8735
8736          normalSizeAnchor = sizeAnchor;
8737
8738          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8739          {
8740             stateAnchor = normalAnchor;
8741             stateSizeAnchor = normalSizeAnchor;
8742
8743             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8744             Position(x,y, w, h, true, true, true, true, false, true);
8745          }
8746       }
8747       get
8748       {
8749          value =
8750          {
8751             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8752             sizeAnchor.isClientW,
8753             sizeAnchor.isClientH
8754          };
8755       }
8756    };
8757
8758    property Size size
8759    {
8760       property_category $"Layout"
8761       isset
8762       {
8763          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8764                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8765             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8766       }
8767       set
8768       {
8769          int x, y, w, h;
8770
8771          sizeAnchor.isClientW = false;
8772          sizeAnchor.isClientH = false;
8773          sizeAnchor.size = value;
8774
8775          normalSizeAnchor = sizeAnchor;
8776
8777          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8778          {
8779             stateAnchor = normalAnchor;
8780             stateSizeAnchor = normalSizeAnchor;
8781
8782             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8783             Position(x, y, w, h, true, true, true, true, false, true);
8784             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8785          }
8786       }
8787       get { value = size; }
8788    };
8789
8790    property Size clientSize
8791    {
8792       property_category $"Layout"
8793       isset
8794       {
8795          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8796                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8797             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8798       }
8799       set
8800       {
8801          int x, y, w, h;
8802          sizeAnchor.isClientW = true;
8803          sizeAnchor.isClientH = true;
8804          sizeAnchor.size = value;
8805
8806          normalSizeAnchor = sizeAnchor;
8807
8808          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8809          {
8810             stateAnchor = normalAnchor;
8811             stateSizeAnchor = normalSizeAnchor;
8812
8813             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8814             Position(x,y, w, h, true, true, true, true, false, true);
8815             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8816          }
8817       }
8818       get { value = this ? clientSize : { 0, 0 }; }
8819    };
8820
8821    property Size initSize { get { value = sizeAnchor.size; } };
8822
8823    property Anchor anchor
8824    {
8825       property_category $"Layout"
8826       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8827
8828       set
8829       {
8830          if(value != null)
8831          {
8832             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8833             {
8834                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8835                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8836             }
8837             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8838             {
8839                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8840                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8841             }
8842             anchor = value;
8843
8844             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type))
8845             {
8846                anchor.left.distance = 0;
8847                anchor.horz.type = 0;
8848             }
8849             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8850             {
8851                anchor.top.distance = 0;
8852                anchor.vert.type = 0;
8853             }
8854
8855             anchored = true;
8856
8857             //if(created)
8858             {
8859                int x, y, w, h;
8860
8861                normalAnchor = anchor;
8862
8863                // Break the anchors for moveable/resizable windows
8864                /*if(style.fixed ) //&& value.left.type == cascade)
8865                {
8866                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8867
8868                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8869                   normalSizeAnchor = SizeAnchor { { w, h } };
8870                   anchored = false;
8871                }*/
8872                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8873                {
8874                   stateAnchor = normalAnchor;
8875                   stateSizeAnchor = normalSizeAnchor;
8876
8877                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8878                   Position(x, y, w, h, true, true, true, true, false, true);
8879                }
8880             }
8881          }
8882          else
8883          {
8884             anchored = false;
8885          }
8886       }
8887       get { value = this ? anchor : Anchor { }; }
8888    };
8889
8890    property Point position
8891    {
8892       property_category $"Layout"
8893       set
8894       {
8895          if(value == null) return;
8896
8897          anchor.left = value.x;
8898          anchor.top  = value.y;
8899          anchor.right.type = none;
8900          anchor.bottom.type = none;
8901          //if(created)
8902          {
8903             int x, y, w, h;
8904
8905             normalAnchor = anchor;
8906
8907             // Break the anchors for moveable/resizable windows
8908             /*
8909             if(style.fixed)
8910             {
8911                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8912
8913                normalAnchor.left = x;
8914                normalAnchor.top = y;
8915                normalAnchor.right.type = none;
8916                normalAnchor.bottom.type = none;
8917                normalSizeAnchor.size.width = w;
8918                normalSizeAnchor.size.height = h;
8919                anchored = false;
8920             }
8921             */
8922             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8923             {
8924                stateAnchor = normalAnchor;
8925                stateSizeAnchor = normalSizeAnchor;
8926
8927                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8928                Position(x,y, w, h, true, true, true, true, false, true);
8929             }
8930          }
8931       }
8932       get { value = position; }
8933    };
8934
8935    property bool disabled
8936    {
8937       property_category $"Behavior"
8938       set
8939       {
8940          if(this && disabled != value)
8941          {
8942             disabled = value;
8943             if(created)
8944                Update(null);
8945          }
8946       }
8947       get { return (bool)disabled; }
8948    };
8949
8950    property bool isEnabled
8951    {
8952       get
8953       {
8954          Window parent;
8955          for(parent = this; parent; parent = parent.parent)
8956             if(parent.disabled)
8957                return false;
8958          return true;
8959       }
8960    };
8961
8962    property WindowState state
8963    {
8964       property_category $"Behavior"
8965       set { SetState(value, false, 0); }
8966       get { return this ? state : 0; }
8967    };
8968
8969    property bool visible
8970    {
8971       property_category $"Behavior"
8972       set
8973       {
8974          if(this && !value && !style.hidden && parent)
8975          {
8976             bool wasActiveChild = parent.activeChild == this;
8977             Window client = null;
8978
8979             style.hidden = true;
8980             if(style.isActiveClient)
8981             {
8982                parent.numPositions--;
8983                if(state == minimized) parent.numIcons--;
8984             }
8985
8986             if(created)
8987             {
8988                OldLink prevOrder = null;
8989
8990                if(rootWindow == this)
8991                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8992                else
8993                {
8994                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8995                   if(style.nonClient)
8996                   {
8997                      box.left   -= parent.clientStart.x;
8998                      box.top    -= parent.clientStart.y;
8999                      box.right  -= parent.clientStart.x;
9000                      box.bottom -= parent.clientStart.y;
9001                   }
9002                   parent.Update(box);
9003                }
9004                if(_isModal && master && master.modalSlave == this)
9005                   master.modalSlave = null;
9006
9007                if(order)
9008                {
9009                   OldLink tmpPrev = order.prev;
9010                   client = tmpPrev ? tmpPrev.data : null;
9011                   if(client && !client.style.hidden && !client.destroyed && client.created)
9012                      prevOrder = tmpPrev;
9013                   for(;;)
9014                   {
9015                      client = tmpPrev ? tmpPrev.data : null;
9016                      if(client == this) { client = null; break; }
9017                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
9018                      {
9019                         tmpPrev = client.order.prev;
9020                      }
9021                      else
9022                      {
9023                         if(client)
9024                            prevOrder = tmpPrev;
9025                         break;
9026                      }
9027                   }
9028
9029                   // If this window can be an active client, make sure the next window we activate can also be one
9030                   if(!style.nonClient && style.isActiveClient)
9031                   {
9032                      tmpPrev = prevOrder;
9033                      for(;;)
9034                      {
9035                         client = tmpPrev ? tmpPrev.data : null;
9036                         if(client == this) { client = null; break; }
9037                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
9038                         {
9039                            tmpPrev = client.order.prev;
9040                         }
9041                         else
9042                         {
9043                            if(client)
9044                               prevOrder = tmpPrev;
9045                            break;
9046                         }
9047                      }
9048                      if(client && client.style.hidden) client = null;
9049                   }
9050                }
9051
9052                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
9053                {
9054                   if(order && prevOrder && prevOrder.data != this)
9055                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
9056                   else
9057                      ActivateEx(false, false, false, true, null, null);
9058
9059                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
9060                   if(parent.activeClient == this)
9061                   {
9062                      parent.activeClient = null;
9063                      parent.UpdateActiveDocument(null);
9064                   }
9065                }
9066                else if(parent.activeClient == this)
9067                {
9068                   parent.activeClient = client;
9069                   parent.UpdateActiveDocument(this);
9070                }
9071
9072                // *** Not doing this anymore ***
9073               /*
9074                if(cycle)
9075                   parent.childrenCycle.Delete(cycle);
9076                if(order)
9077                   parent.childrenOrder.Delete(order);
9078                cycle = null;
9079                order = null;
9080                */
9081
9082                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9083             }
9084
9085             firewatchers;
9086          }
9087          else if(this && value && style.hidden)
9088          {
9089             style.hidden = false;
9090             if(created)
9091             {
9092                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9093                if(rootWindow == this)
9094                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
9095
9096                if(_isModal && master)
9097                   master.modalSlave = this;
9098
9099                if(style.isActiveClient)
9100                {
9101                   positionID = parent.GetPositionID(this);
9102                   parent.numPositions++;
9103                   if(state == minimized) parent.numIcons++;
9104                }
9105
9106                // *** NOT DOING THIS ANYMORE ***
9107                /*
9108                if(!(style.inactive))
9109                {
9110                   if(!(style.noCycle))
9111                   {
9112                      cycle = parent.childrenCycle.AddAfter(
9113                         (parent.activeChild && parent.activeChild.cycle) ?
9114                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
9115                      cycle.data = this;
9116                   }
9117                   order = parent.childrenOrder.AddAfter(
9118                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
9119                      sizeof(OldLink));
9120                   order.data = this;
9121                }
9122                */
9123
9124                /*
9125                if(true || !parent.activeChild)
9126                   ActivateEx(true, false, true, true, null, null);
9127                */
9128                if(creationActivation == activate)
9129                   ActivateEx(true, false, true, true, null, null);
9130                else if(creationActivation == flash && !object)
9131                   Flash();
9132
9133                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9134                Update(null);
9135
9136                // rootWindow.
9137                ConsequentialMouseMove(false);
9138             }
9139
9140             firewatchers;
9141          }
9142          else if(this)
9143             style.hidden = !value;
9144       }
9145
9146       get { return (style.hidden || !setVisible) ? false : true; }
9147    };
9148
9149    property bool isDocument
9150    {
9151       property_category $"Document"
9152       set { style.isDocument = value; if(value) SetupFileMonitor(); }
9153       get { return style.isDocument; }
9154    };
9155
9156    property bool mergeMenus
9157    {
9158       property_category $"Window Style"
9159       set { mergeMenus = value; }
9160       get { return (bool)mergeMenus; }
9161    };
9162
9163    property bool hasHorzScroll
9164    {
9165       property_category $"Window Style"
9166       set
9167       {
9168          if(value)
9169          {
9170             if(!style.hasHorzScroll && created)
9171             {
9172                CreateSystemChildren();
9173                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9174             }
9175          }
9176          else if(style.hasHorzScroll)
9177          {
9178             sbh.Destroy(0);
9179             sbh = null;
9180             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9181          }
9182          style.hasHorzScroll = value;
9183       }
9184
9185       get { return style.hasHorzScroll; }
9186    };
9187
9188    property bool hasVertScroll
9189    {
9190       property_category $"Window Style"
9191       set
9192       {
9193          if(value)
9194          {
9195             if(!style.hasVertScroll && created)
9196             {
9197                style.hasVertScroll = true;
9198                CreateSystemChildren();
9199                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9200             }
9201          }
9202          else if(style.hasVertScroll)
9203          {
9204             sbv.Destroy(0);
9205             sbv = null;
9206             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9207          }
9208          style.hasVertScroll = value;
9209       }
9210       get { return style.hasVertScroll; }
9211    };
9212
9213    property bool dontHideScroll
9214    {
9215       property_category $"Behavior"
9216       set
9217       {
9218          scrollFlags.dontHide = value;
9219          if(value)
9220          {
9221             //UpdateScrollBars(true, true);
9222             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9223          }
9224          else
9225          {
9226             // UpdateScrollBars(true, true);
9227             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9228          }
9229       }
9230       get { return scrollFlags.dontHide; }
9231    };
9232
9233    property bool dontScrollVert
9234    {
9235       property_category $"Behavior"
9236       set { style.dontScrollVert = value; }
9237       get { return style.dontScrollVert; }
9238    };
9239    property bool dontScrollHorz
9240    {
9241       property_category $"Behavior"
9242       set { style.dontScrollHorz = value; }
9243       get { return style.dontScrollHorz; }
9244    };
9245
9246    property bool snapVertScroll
9247    {
9248       property_category $"Behavior"
9249       set
9250       {
9251          scrollFlags.snapY = value;
9252          if(sbv) sbv.snap = value;
9253       }
9254       get { return scrollFlags.snapY; }
9255    };
9256    property bool snapHorzScroll
9257    {
9258        property_category $"Behavior"
9259       set
9260       {
9261          scrollFlags.snapX = value;
9262          if(sbh) sbh.snap = value;
9263       }
9264       get { return scrollFlags.snapX; }
9265    };
9266
9267    property Point scroll
9268    {
9269       property_category $"Behavior"
9270       set { if(this) SetScrollPosition(value.x, value.y); }
9271       get { value = scroll; }
9272    };
9273
9274    property bool modifyVirtualArea
9275    {
9276       property_category $"Behavior"
9277       set { modifyVirtArea = value; }
9278       get { return (bool)modifyVirtArea; }
9279    };
9280
9281    property bool dontAutoScrollArea
9282    {
9283       property_category $"Behavior"
9284       // Activating a child control out of view will automatically scroll to make it in view
9285       set { noAutoScrollArea = value; }
9286       get { return (bool)noAutoScrollArea; }
9287    };
9288
9289    property const char * fileName
9290    {
9291       property_category $"Document"
9292       set
9293       {
9294          SetupFileMonitor();
9295
9296          if(menu && ((!fileName && value) || (fileName && !value)))
9297          {
9298             MenuItem item = menu.FindItem(MenuFileSave, 0);
9299             if(item) item.disabled = !modifiedDocument && value;
9300          }
9301
9302          delete fileName;
9303
9304          if(value && value[0])
9305             fileName = CopyString(value);
9306
9307          if(parent && this == parent.activeClient)
9308             parent.UpdateActiveDocument(null);
9309          else
9310             UpdateCaption();
9311
9312          // if(style.isDocument)
9313          if(!saving)
9314             fileMonitor.fileName = value;
9315       }
9316       get { return fileName; }
9317    };
9318
9319    property int64 id
9320    {
9321       property_category $"Data"
9322       set { id = value; }
9323       get { return id; }
9324    };
9325
9326    property bool modifiedDocument
9327    {
9328       property_category $"Document"
9329       set
9330       {
9331          if(style.isDocument || fileName)
9332          {
9333             if(menu)
9334             {
9335                MenuItem item = menu.FindItem(MenuFileSave, 0);
9336                if(item) item.disabled = !value && fileName;
9337             }
9338          }
9339
9340          if(modifiedDocument != value)
9341          {
9342             modifiedDocument = value;
9343             if(style.isDocument || fileName)
9344                UpdateCaption();
9345          }
9346       }
9347       get { return (bool)modifiedDocument; }
9348    };
9349
9350    property bool showInTaskBar
9351    {
9352       property_category $"Window Style"
9353       set { style.showInTaskBar = value; }
9354       get { return style.showInTaskBar; }
9355    };
9356    property FileDialog saveDialog { set { saveDialog = value; } };
9357    property bool isActiveClient
9358    {
9359       property_category $"Behavior"
9360       set
9361       {
9362          if(parent && style.isActiveClient != value && !style.hidden)
9363          {
9364             if(value)
9365             {
9366                if(state == minimized) parent.numIcons++;
9367                parent.numPositions++;
9368             }
9369             else
9370             {
9371                if(state == minimized) parent.numIcons--;
9372                parent.numPositions--;
9373             }
9374          }
9375          style.isActiveClient = value;
9376       }
9377       get { return style.isActiveClient; }
9378    };
9379
9380    property Cursor cursor
9381    {
9382       property_category $"Appearance"
9383       set
9384       {
9385          cursor = value;
9386          SelectMouseCursor();
9387       }
9388       get { return cursor; }
9389    };
9390
9391 //#if !defined(ECERE_VANILLA)
9392    property const char * name
9393    {
9394       property_category $"Design"
9395       get
9396       {
9397          return (this && object) ? object.name : null;
9398       }
9399       set
9400       {
9401          if(activeDesigner)
9402             activeDesigner.RenameObject(object, value);
9403       }
9404    };
9405 //#endif
9406    property const char * displayDriver
9407    {
9408       property_category $"Behavior"
9409       set
9410       {
9411          dispDriver = GetDisplayDriver(value);
9412          //DisplayModeChanged();
9413       }
9414       get
9415       {
9416          return dispDriver ? dispDriver.name : null;
9417       }
9418    }
9419
9420    // RUNTIME PROPERTIES
9421    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9422    property Size scrollArea
9423    {
9424       property_category $"Behavior"
9425       set
9426       {
9427          if(value != null)
9428             SetScrollArea(value.w, value.h, false);
9429          else
9430             SetScrollArea(0,0, true);
9431       }
9432       get { value = scrollArea; }
9433       isset
9434       {
9435          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9436       }
9437    };
9438    property bool is3D
9439    {
9440       property_category $"Layout"
9441       set { if(this) is3D = value; }
9442       get { return (bool)is3D; }
9443    };
9444
9445    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9446
9447    // Will be merged with font later
9448    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9449    property Point clientStart { get { value = clientStart; } };
9450    property Point absPosition { get { value = absPosition; } };
9451    property Anchor normalAnchor { get { value = normalAnchor; } };
9452    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9453    property bool active { get { return (bool)active; } };
9454    property bool created { get { return (bool)created; } };
9455    property bool destroyed { get { return (bool)destroyed; } };
9456    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9457    property Window firstChild { get { return children.first; } };
9458    property Window lastChild { get { return children.last; } };
9459    property Window activeClient { get { return activeClient; } };
9460    property Window activeChild { get { return activeChild; } };
9461    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9462    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9463    property ScrollBar horzScroll { get { return sbh; } };
9464    property ScrollBar vertScroll { get { return sbv; } };
9465    property StatusBar statusBar { get { return statusBar; } };
9466    property Window rootWindow { get { return rootWindow; } };
9467    property bool closing { get { return (bool)closing; } set { closing = value; } };
9468    property int documentID { get { return documentID; } };
9469    property Window previous { get { return prev; } }
9470    property Window next { get { return next; } }
9471    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9472    property PopupMenu menuBar { get { return menuBar; } }
9473    property ScrollBar sbv { get { return sbv; } }
9474    property ScrollBar sbh { get { return sbh; } }
9475    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9476    property void * systemHandle { get { return windowHandle; } }
9477    property Button minimizeButton { get { return sysButtons[0]; } };
9478    property Button maximizeButton { get { return sysButtons[1]; } };
9479    property Button closeButton { get { return sysButtons[2]; } };
9480    property BitmapResource icon
9481    {
9482       get { return icon; }
9483       set
9484       {
9485          icon = value;
9486          if(icon) incref icon;
9487          if(created)
9488             guiApp.interfaceDriver.SetIcon(this, value);
9489       }
9490    };
9491    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9492    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9493    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9494    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9495    property bool nativeDecorations
9496    {
9497       get { return (bool)nativeDecorations; }
9498       set { nativeDecorations = value; }
9499 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9500       isset
9501       {
9502          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9503          bool result = false;
9504          if(nativeDecorations)
9505          {
9506             if(rootWindow == this)
9507                result = true;
9508             else
9509             {
9510                if(formDesigner && activeDesigner)
9511                {
9512                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9513                   Window form = cd ? cd.form : null;
9514                   if(form && parent == form.parent)
9515                      result = true;
9516                }
9517             }
9518          }
9519          return result != style.fixed;
9520       }
9521 #endif
9522    };
9523    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9524
9525    property const char * text
9526    {
9527       property_category $"Deprecated"
9528       watchable
9529       set { property::caption = value; }
9530       get { return property::caption; }
9531    }
9532 private:
9533    // Data
9534    //char * yo;
9535    Window prev, next;
9536    WindowBits style;       // Window Style
9537    char * caption;            // Name / Caption
9538    Window parent;    // Parent window
9539    OldList children;          // List of children in Z order
9540    Window activeChild;     // Child window having focus
9541    Window activeClient;
9542    Window previousActive;  // Child active prior to activating the default child
9543    Window master;          // Window owning and receiving notifications concerning this window
9544    OldList slaves;            // List of windows belonging to this window
9545    Display display;        // Display this window is drawn into
9546
9547    Point position;         // Position in parent window client area
9548    Point absPosition;      // Absolute position
9549    Point clientStart;      // Client area position from (0,0) in this window
9550    Size size;              // Size
9551    Size clientSize;        // Client area size
9552    Size scrollArea;        // Virtual Scroll area size
9553    Size reqScrollArea;     // Requested virtual area size
9554    Point scroll;           // Virtual area scrolling position
9555    ScrollBar sbh, sbv;        // Scrollbar window handles
9556    Cursor cursor;        // Mouse cursor used for this window
9557    WindowState state;
9558    PopupMenu menuBar;
9559    StatusBar statusBar;
9560    Button sysButtons[3];
9561    char * fileName;
9562    Box clientArea;         // Client Area box clipped to parent
9563    Key setHotKey;
9564    HotKeySlot hotKey;        // HotKey for this window
9565    int numDocuments;
9566    int numPositions;
9567    Menu menu;
9568    ScrollFlags scrollFlags;// Window Scrollbar Flags
9569    int64 id;                 // Control ID
9570    int documentID;
9571    ColorAlpha background;  // Background color used to draw the window area
9572    Color foreground;
9573    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9574    OldList childrenCycle;     // Cycling order
9575    OldLink cycle;             // Element of parent's cycling order
9576    OldList childrenOrder;     // Circular Z-Order
9577    OldLink order;             // Element of parent's circular Z-Order
9578    Window modalSlave;      // Slave window blocking this window's interaction
9579
9580    Window rootWindow;      // Topmost system managed window
9581    void * windowHandle;    // System window handle
9582
9583    DialogResult returnCode;// Return code for modal windows
9584
9585    Point sbStep;           // Scrollbar line scrolling steps
9586
9587    Anchor stateAnchor;
9588    SizeAnchor stateSizeAnchor;
9589
9590    Anchor normalAnchor;
9591    SizeAnchor normalSizeAnchor;
9592
9593    Size skinMinSize;       // Minimal window size based on style
9594    Point scrolledPos;      // Scrolled position
9595    Box box;                // Window box clipped to parent
9596    Box * against;          // What to clip the box to
9597
9598    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9599    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9600    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9601    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9602    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9603    Point scrolledArea;     // Distance to scroll area by
9604    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9605
9606    OldList hotKeys;           // List of the hotkeys of all children
9607    Window defaultControl;  // Default child control
9608    Size minSize;
9609    Size maxSize;
9610
9611    ColorAlpha * palette;   // Color palette used for this window
9612
9613    int caretSize;          // Size of caret, non zero if a caret is present
9614    Point caretPos;         // Caret position
9615
9616    void * systemParent;    // Parent System Window for embedded windows
9617
9618    int iconID;
9619    int numIcons;
9620    int positionID;
9621
9622    Mutex mutex;
9623    WindowState lastState;
9624
9625    FileMonitor fileMonitor;
9626
9627    FontResource setFont, systemFont;
9628    FontResource usedFont;
9629    FontResource captionFont;
9630    OldList resources;
9631    FileDialog saveDialog;
9632    Anchor anchor;
9633    SizeAnchor sizeAnchor;
9634
9635    // FormDesigner data
9636    ObjectInfo object;
9637    Window control;
9638    Extent * tempExtents; //[4];
9639    BitmapResource icon;
9640    void * windowData;
9641    CreationActivationOption creationActivation;
9642    struct
9643    {
9644       bool active:1;            // true if window and ancestors are active
9645       bool acquiredInput:1;     // true if the window is processing state based input
9646       bool modifiedDocument:1;
9647       bool disabled:1;          // true if window cannot interact
9648       bool isForegroundWindow:1;// true while a root window is being activated
9649       bool visible:1;           // Visibility flag
9650       bool destroyed:1;         // true if window is being destroyed
9651       bool anchored:1;          // true if this window is repositioned when the parent resizes
9652       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9653       bool mouseInside:1;
9654       bool positioned:1;
9655       bool created:1;
9656       bool is3D:1;
9657       bool mergeMenus:1;
9658       bool modifyVirtArea:1;
9659       bool noAutoScrollArea:1;
9660       bool closing:1;
9661       bool autoCreate:1;
9662       bool setVisible:1;      // FOR FORM DESIGNER
9663       bool wasCreated:1;
9664       bool fullRender:1;
9665       bool moveable:1;
9666       bool alphaBlend:1;
9667       bool composing:1;
9668       bool useSharedMemory:1;
9669       bool resized:1;
9670       bool saving:1;
9671       bool nativeDecorations:1;
9672       bool manageDisplay:1;
9673       bool formDesigner:1; // True if we this is running in the form editor
9674       bool requireRemaximize:1;
9675    };
9676
9677    // Checks used internally for them not to take effect in FormDesigner
9678    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9679    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9680
9681    WindowController controller;
9682    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9683 };
9684
9685 public class CommonControl : Window
9686 {
9687    // creationActivation = doNothing;
9688
9689    ToolTip toolTip;
9690    public property const String toolTip
9691    {
9692       property_category $"Appearance"
9693       set
9694       {
9695          if(created) CommonControl::OnDestroy();
9696          delete toolTip;
9697          toolTip = value ? ToolTip { tip = value; } : null;
9698          incref toolTip;
9699          if(created) CommonControl::OnCreate();
9700       }
9701       get { return toolTip ? toolTip.tip : null; }
9702    }
9703
9704    void OnDestroy()
9705    {
9706       if(toolTip)
9707          // (Very) Ugly work around for the fact that the parent watcher
9708          // won't fire when it's already been disconnected...
9709          eInstance_FireSelfWatchers(toolTip,
9710             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9711    }
9712
9713    bool OnCreate()
9714    {
9715       if(toolTip)
9716          toolTip.parent = this;
9717       return true;
9718    }
9719    ~CommonControl()
9720    {
9721       delete toolTip;
9722    }
9723 };
9724
9725 public class Percentage : float
9726 {
9727    const char * OnGetString(char * string, float * fieldData, bool * needClass)
9728    {
9729       int c;
9730       int last = 0;
9731       sprintf(string, "%.2f", this);
9732       c = strlen(string)-1;
9733       for( ; c >= 0; c--)
9734       {
9735          if(string[c] != '0')
9736             last = Max(last, c);
9737          if(string[c] == '.')
9738          {
9739             if(last == c)
9740                string[c] = 0;
9741             else
9742                string[last+1] = 0;
9743             break;
9744          }
9745       }
9746       return string;
9747    }
9748 };
9749
9750 public void ApplySkin(Class c, const char * name, void ** vTbl)
9751 {
9752    char className[1024];
9753    Class sc;
9754    OldLink d;
9755    int m;
9756
9757    subclass(Window) wc = (subclass(Window))c;
9758    subclass(Window) base = (subclass(Window))c.base;
9759
9760    sprintf(className, "%sSkin_%s", name, c.name);
9761    wc.pureVTbl = c._vTbl;
9762    c._vTbl = new void *[c.vTblSize];
9763    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9764    sc = eSystem_FindClass(c.module.application, className);
9765
9766    if(vTbl)
9767    {
9768       for(m = 0; m < c.base.vTblSize; m++)
9769       {
9770          if(c._vTbl[m] == base.pureVTbl[m])
9771             c._vTbl[m] = vTbl[m];
9772       }
9773    }
9774    if(sc)
9775    {
9776       for(m = 0; m < c.vTblSize; m++)
9777       {
9778          if(sc._vTbl[m] != wc.pureVTbl[m])
9779             c._vTbl[m] = sc._vTbl[m];
9780       }
9781    }
9782
9783    for(d = c.derivatives.first; d; d = d.next)
9784    {
9785       ApplySkin(d.data, name, c._vTbl);
9786    }
9787 }
9788
9789 public void UnapplySkin(Class c)
9790 {
9791    subclass(Window) wc = (subclass(Window))c;
9792    OldLink d;
9793
9794    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9795    {
9796       delete c._vTbl;
9797       c._vTbl = wc.pureVTbl;
9798       wc.pureVTbl = null;
9799    }
9800
9801    for(d = c.derivatives.first; d; d = d.next)
9802    {
9803       UnapplySkin(d.data);
9804    }
9805 }
9806 /*
9807 void CheckFontIntegrity(Window window)
9808 {
9809    Window c;
9810    if(window)
9811    {
9812       if(window.usedFont && window.usedFont.font == 0xecececec)
9813       {
9814          FontResource uf = window.usedFont;
9815          char * className = window._class.name;
9816          char * text = window.text;
9817          Print("");
9818       }
9819       for(c = window.firstChild; c; c = c.next)
9820          CheckFontIntegrity(c);
9821    }
9822 }*/
9823
9824 public class ControllableWindow : Window
9825 {
9826    /*WindowController controller;
9827    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9828    ~ControllableWindow() { delete controller; }*/
9829 }
9830
9831 class WindowControllerInterface : ControllableWindow
9832 {
9833    bool OnKeyDown(Key key, unichar ch)
9834    {
9835       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch);
9836       if(result)
9837          result = ((bool (*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown])(controller.window, key, ch);
9838       return result;
9839    }
9840
9841    bool OnKeyUp(Key key, unichar ch)
9842    {
9843       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch);
9844       if(result)
9845          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp])(controller.window, key, ch);
9846       return result;
9847    }
9848
9849    bool OnKeyHit(Key key, unichar ch)
9850    {
9851       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch);
9852       if(result)
9853          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit])(controller.window, key, ch);
9854       return result;
9855    }
9856
9857    bool OnMouseMove(int x, int y, Modifiers mods)
9858    {
9859       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods);
9860       if(result)
9861          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove])(controller.window, x, y, mods);
9862       return result;
9863    }
9864
9865    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9866    {
9867       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods);
9868       if(result)
9869          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown])(controller.window, x, y, mods);
9870       return result;
9871    }
9872
9873    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9874    {
9875       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods);
9876       if(result)
9877          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp])(controller.window, x, y, mods);
9878       return result;
9879    }
9880
9881    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9882    {
9883       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9884       if(result)
9885          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick])(controller.window, x, y, mods);
9886       return result;
9887    }
9888
9889    bool OnRightButtonDown(int x, int y, Modifiers mods)
9890    {
9891       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods);
9892       if(result)
9893          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown])(controller.window, x, y, mods);
9894       return result;
9895    }
9896
9897    bool OnRightButtonUp(int x, int y, Modifiers mods)
9898    {
9899       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods);
9900       if(result)
9901          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp])(controller.window, x, y, mods);
9902       return result;
9903    }
9904
9905    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9906    {
9907       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9908       if(result)
9909          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick])(controller.window, x, y, mods);
9910       return result;
9911    }
9912
9913    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9914    {
9915       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods);
9916       if(result)
9917          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown])(controller.window, x, y, mods);
9918       return result;
9919    }
9920
9921    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9922    {
9923       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods);
9924       if(result)
9925          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp])(controller.window, x, y, mods);
9926       return result;
9927    }
9928
9929    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9930    {
9931       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9932       if(result)
9933          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick])(controller.window, x, y, mods);
9934       return result;
9935    }
9936
9937    void OnResize(int width, int height)
9938    {
9939       ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
9940       ((void(*)(Window, int, int))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize])(controller.window, width, height);
9941    }
9942
9943    void OnRedraw(Surface surface)
9944    {
9945       ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
9946       ((void(*)(Window, Surface))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(controller.window, surface);
9947    }
9948
9949    bool OnCreate()
9950    {
9951       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller);
9952       if(result)
9953          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate])(controller.window);
9954       return result;
9955    }
9956
9957    bool OnLoadGraphics()
9958    {
9959       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller);
9960       if(result)
9961          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics])(controller.window);
9962       return result;
9963    }
9964
9965    void OnUnloadGraphics()
9966    {
9967       ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
9968       ((void(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics])(controller.window);
9969    }
9970 }
9971
9972 public class WindowController<class V>
9973 {
9974 public:
9975    property Window window
9976    {
9977       set
9978       {
9979          uint size = class(Window).vTblSize;
9980          if(value)
9981          {
9982             windowVTbl = new void *[size];
9983             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9984             if(value._vTbl == value._class._vTbl)
9985             {
9986                value._vTbl = new void *[value._class.vTblSize];
9987                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9988             }
9989             {
9990                int c;
9991                for(c = 0; c < size; c++)
9992                {
9993                   void * function = class(WindowControllerInterface)._vTbl[c];
9994                   if(function != DefaultFunction)
9995                      value._vTbl[c] = function;
9996                   else
9997                      value._vTbl[c] = windowVTbl[c];
9998                }
9999             }
10000          }
10001          else
10002             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
10003          window = value;
10004       }
10005       get { return window; }
10006    }
10007    property V controlled
10008    {
10009       set { controlled = value; }
10010       get { return controlled; }
10011    }
10012    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
10013    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
10014    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
10015    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
10016    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
10017    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
10018    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10019    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
10020    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
10021    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10022    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
10023    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
10024    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10025    virtual void V::OnResize(WindowController controller, int width, int height);
10026    virtual void V::OnRedraw(WindowController controller, Surface surface);
10027    virtual bool V::OnCreate(WindowController controller);
10028    virtual bool V::OnLoadGraphics(WindowController controller);
10029    virtual void V::OnUnloadGraphics(WindowController controller);
10030
10031 private:
10032    int (** windowVTbl)();
10033    V controlled;
10034    Window window;
10035
10036    ~WindowController()
10037    {
10038       delete windowVTbl;
10039    }
10040 }