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