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