ecere/gui/Window: Fixed caret showing on disabled controls
[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 && isEnabled)
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          if(!windowHandle)
4836             windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
4837
4838          // This was here, is it really needed?
4839          //guiApp.interfaceDriver.ActivateRootWindow(this);
4840
4841          if(!displaySystem)
4842          {
4843             displaySystem = DisplaySystem {};
4844             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
4845             {
4846                delete displaySystem;
4847             }
4848          }
4849          if(displaySystem)
4850          {
4851             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
4852             if(display.Create(displaySystem, windowHandle))
4853                result = true;
4854             else
4855             {
4856                delete display;
4857             }
4858          }
4859          // Sometimes icon does not show up on Windows XP if we set here...
4860          // guiApp.interfaceDriver.SetIcon(this, icon);
4861       }
4862       else if(this != guiApp.desktop)
4863       {
4864          display = rootWindow ? rootWindow.display : null;
4865          result = true;
4866       }
4867       else
4868          result = true;
4869
4870       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
4871          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
4872
4873       for(child = children.first; child; child = child.next)
4874       {
4875          if(child.created && !child.Setup(false))
4876             result = false;
4877
4878          if(guiApp.modeSwitching && guiApp.fullScreen && child.rootWindow == child)
4879             child.UpdateCaption();
4880       }
4881       return result;
4882    }
4883
4884    bool SetupDisplay(void)
4885    {
4886 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
4887       if(is3D) return Window3D_SetupDisplay(this); else
4888 #endif
4889       if(SetupRoot())
4890          return Setup(true);
4891       return false;
4892    }
4893
4894    class_data void ** pureVTbl;
4895
4896    bool LoadGraphics(bool creation, bool resetAnchors)
4897    {
4898       bool result = false;
4899       bool success = false;
4900       Window child;
4901       WindowState stateBackup = state;
4902
4903       if(((subclass(Window))_class).pureVTbl)
4904       {
4905          if(_vTbl == _class._vTbl)
4906          {
4907             _vTbl = ((subclass(Window))_class).pureVTbl;
4908          }
4909          else
4910          {
4911             int m;
4912             for(m = 0; m < _class.vTblSize; m++)
4913             {
4914                if(_vTbl[m] == _class._vTbl[m])
4915                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
4916             }
4917          }
4918       }
4919       if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
4920       {
4921          if(_vTbl == ((subclass(Window))_class).pureVTbl)
4922          {
4923             _vTbl = _class._vTbl;
4924          }
4925          else
4926          {
4927             int m;
4928             for(m = 0; m < _class.vTblSize; m++)
4929             {
4930                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
4931                   _vTbl[m] = _class._vTbl[m];
4932             }
4933          }
4934       }
4935
4936       if(guiApp.fullScreenMode || this != guiApp.desktop)
4937       {
4938          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
4939          if(display)
4940          {
4941             ResPtr ptr;
4942             success = true;
4943
4944             display.Lock(false);
4945             if(rootWindow == this)
4946             {
4947                // Set Color Palette
4948                display.SetPalette(palette, true);
4949
4950                // Load Cursors
4951                /*
4952                if(guiApp.fullScreenMode && this == guiApp.desktop)
4953                {
4954                   int c;
4955                   Cursor cursor;
4956
4957                   for(c=0; c<SystemCursor::enumSize; c++)
4958                      if(!guiApp.systemCursors[c].bitmap)
4959                      {
4960                         guiApp.systemCursors[c].bitmapName = guiApp.currentSkin.CursorsBitmaps(c,
4961                            &guiApp.systemCursors[c].hotSpotX,&guiApp.systemCursors[c].hotSpotY, &guiApp.systemCursors[c].paletteShades);
4962                         if(guiApp.systemCursors[c].bitmapName)
4963                         {
4964                            guiApp.systemCursors[c].bitmap = eBitmap_LoadT(guiApp.systemCursors[c].bitmapName, null,
4965                               guiApp.systemCursors[c].paletteShades ? null : guiApp.desktop.display.displaySystem);
4966                            if(guiApp.systemCursors[c].bitmap)
4967                               guiApp.systemCursors[c].bitmap.paletteShades = guiApp.systemCursors[c].paletteShades;
4968                            else
4969                               success = false;
4970                         }
4971                      }
4972                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
4973                   {
4974                      cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null,
4975                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
4976                      if(cursor.bitmap)
4977                         cursor.bitmap.paletteShades = cursor.paletteShades;
4978                      else
4979                         success = false;
4980                   }
4981                   guiApp.cursorUpdate = true;
4982
4983                   display.Unlock();
4984                   ConsequentialMouseMove(false);
4985                   display.Lock(true);
4986                }
4987                */
4988             }
4989
4990             // Load Window Graphic Resources
4991
4992             /*
4993             if(usedFont == setFont || usedFont == window.systemFont)
4994                RemoveResource(usedFont);
4995             */
4996             if(setFont)
4997                RemoveResource(setFont); // TESTING setFont instead of usedFont);
4998
4999             if(systemFont)
5000                RemoveResource(systemFont);
5001
5002             if(captionFont)
5003                RemoveResource(captionFont);
5004
5005             for(ptr = resources.first; ptr; ptr = ptr.next)
5006             {
5007                ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
5008             }
5009             if(setFont)
5010                AddResource(setFont);
5011             if(systemFont)
5012                AddResource(systemFont);
5013
5014             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
5015
5016             firewatchers font;
5017
5018             /*
5019             if(!setFont)
5020             {
5021                //if(master && master.font)
5022                if(parent && parent.font)
5023                {
5024                   font = FontResource
5025                   {
5026                      faceName = parent.font.faceName,
5027                      size = parent.font.size,
5028                      bold = parent.font.bold,
5029                      italic = parent.font.italic,
5030                      underline = parent.font.underline
5031                   };
5032                   //font = parent.font;
5033                   watch(parent) { font { } };
5034                }
5035                else
5036                   font = guiApp.currentSkin.SystemFont();
5037                AddResource(font);
5038
5039                firewatchers font;
5040             }
5041             */
5042
5043             captionFont = guiApp.currentSkin ? guiApp.currentSkin.CaptionFont() : null;
5044             AddResource(captionFont);
5045
5046             if(OnLoadGraphics())
5047             {
5048                int x,y,w,h;
5049
5050                display.Unlock();
5051
5052                //SetScrollLineStep(sbStep.x, sbStep.y);
5053
5054                if(this != guiApp.desktop)
5055                {
5056                   if(resetAnchors)
5057                   {
5058                      normalAnchor = anchor;
5059                      normalSizeAnchor = sizeAnchor;
5060                   }
5061
5062                   // Break the anchors for moveable/resizable windows
5063                   /*
5064                   if(style.fixed && style.isDocument)
5065                   {
5066                      ComputeAnchors(ax, ay, aw, ah, &x, &y, &w, &h);
5067                      ax = x;
5068                      ay = y;
5069                      aw = w;
5070                      ah = h;
5071                      anchored = false;
5072                   }
5073                   */
5074                   switch(state)
5075                   {
5076                      case maximized:
5077
5078                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5079                         stateSizeAnchor = SizeAnchor {};
5080                         break;
5081
5082                      case minimized:
5083                      {
5084                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5085
5086                         stateAnchor =
5087                            Anchor
5088                            {
5089                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
5090                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
5091                            };
5092
5093                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5094                         break;
5095                      }
5096                      case normal:
5097                         stateAnchor = normalAnchor;
5098                         stateSizeAnchor = normalSizeAnchor;
5099                         break;
5100                   }
5101                   position = Point { };
5102                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5103
5104                }
5105                else
5106                {
5107                   x = scrolledPos.x;
5108                   y = scrolledPos.y;
5109                   w = size.w;
5110                   h = size.h;
5111                }
5112
5113                if(Position(x, y, w, h, true, false, true, true, true, true))
5114                {
5115                   if((this != guiApp.desktop || guiApp.fullScreenMode) && rootWindow == this)
5116                   {
5117                      if(!style.hidden)
5118                         guiApp.interfaceDriver.SetRootWindowState(this, normal, true);
5119                   }
5120
5121                   Update(null);
5122
5123                   result = true;
5124                }
5125             }
5126             else
5127             {
5128                result = false;
5129                display.Unlock();
5130             }
5131          }
5132       }
5133       else
5134       {
5135          success = result = true;
5136       }
5137
5138       if(!creation && result)
5139       {
5140          // Load menu bar first because sys buttons are on it...
5141          if(menuBar)
5142          {
5143             if(!menuBar.LoadGraphics(false, resetAnchors))
5144             {
5145                result = false;
5146                success = false;
5147             }
5148          }
5149          for(child = children.first; child; child = child.next)
5150          {
5151             if(child.created && child != menuBar && !child.LoadGraphics(false, resetAnchors))
5152             {
5153                result = false;
5154                success = false;
5155             }
5156          }
5157          if(!creation)
5158             CreateSystemChildren();
5159
5160          OnApplyGraphics();
5161       }
5162       if(this == guiApp.desktop && !guiApp.fullScreenMode)
5163       {
5164          if(activeChild)
5165             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
5166       }
5167       /*
5168       TODO:
5169       if(!success)
5170          //guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, caption);
5171          guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, class.name);
5172       */
5173
5174       // Do this here to avoid problems on Windows
5175       if(stateBackup == maximized)
5176          property::state = maximized;
5177       return result;
5178    }
5179
5180    void UnloadGraphics(bool destroyWindows)
5181    {
5182       Window child;
5183
5184       // Free children's graphics
5185       for(child = children.first; child; child = child.next)
5186          child.UnloadGraphics(destroyWindows);
5187
5188       if(display)
5189          display.Lock(false);
5190
5191       // Free cursors
5192       if(guiApp.fullScreenMode && this == guiApp.desktop)
5193       {
5194          Cursor cursor;
5195          SystemCursor c;
5196
5197          for(c=0; c<SystemCursor::enumSize; c++)
5198             if(guiApp.systemCursors[c].bitmap)
5199                delete guiApp.systemCursors[c].bitmap;
5200
5201          for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5202             delete cursor.bitmap;
5203
5204          guiApp.cursorBackground.Free();
5205       }
5206
5207       if(display && display.displaySystem)
5208       {
5209          ResPtr ptr;
5210
5211          for(ptr = resources.first; ptr; ptr = ptr.next)
5212          {
5213             if(ptr.loaded)
5214             {
5215                display.displaySystem.UnloadResource(ptr.resource, ptr.loaded);
5216                ptr.loaded = null;
5217             }
5218          }
5219
5220          // Free window graphics
5221          OnUnloadGraphics();
5222
5223          // Free skin graphics
5224          if(rootWindow == this)
5225          {
5226             DisplaySystem displaySystem = display.displaySystem;
5227             if(is3D)
5228             {
5229                display.driverData = null;
5230                display.displaySystem = null;
5231             }
5232             display.Unlock();
5233             delete display;
5234             if(displaySystem && !displaySystem.numDisplays && !is3D)
5235                delete displaySystem;
5236          }
5237          else
5238          {
5239             display.Unlock();
5240             display = null;
5241          }
5242       }
5243
5244       if(guiApp.acquiredWindow && this == guiApp.acquiredWindow.rootWindow)
5245          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, false);
5246
5247       if(this == guiApp.desktop || parent == guiApp.desktop)
5248       {
5249          if((guiApp.fullScreenMode || this != guiApp.desktop) && rootWindow == this && windowHandle && destroyWindows)
5250             guiApp.interfaceDriver.DestroyRootWindow(this);
5251       }
5252    }
5253
5254    // --- Window Hiding ---
5255
5256    void SetVisibility(bool state)
5257    {
5258       bool visible = (style.hidden || !created) ? false : state;
5259       if(visible != this.visible)
5260       {
5261          Window child;
5262
5263          this.visible = visible;
5264          for(child = children.first; child; child = child.next)
5265             child.SetVisibility(visible);
5266          Update(null);
5267          ConsequentialMouseMove(false);
5268          if(parent && !nonClient) parent.OnChildVisibilityToggled(this, visible);
5269       }
5270    }
5271
5272    // --- Windows and graphics initialization / termination ---
5273
5274    bool DisplayModeChanged(void)
5275    {
5276       bool result = false;
5277       if(!guiApp.fullScreenMode && !guiApp.modeSwitching/* && guiApp.desktop.active*/)
5278       {
5279          guiApp.modeSwitching = true;
5280          UnloadGraphics(false);
5281          if(SetupDisplay())
5282             if(LoadGraphics(false, false))
5283                result = true;
5284          guiApp.modeSwitching = false;
5285       }
5286       return result;
5287    }
5288
5289    // --- Window updates system ---
5290
5291    void UpdateDirty(Box updateBox)
5292    {
5293       if(!manageDisplay) { OnRedraw(null);return; }
5294       if(visible)
5295       {
5296          if(display && (!guiApp.fullScreenMode || guiApp.desktop.active) && !guiApp.modeSwitching)
5297          {
5298             display.Lock(true);
5299             if(display.flags.flipping)
5300             {
5301                Update(null);
5302                rootWindow.UpdateDisplay();
5303             }
5304             else
5305                UpdateBackDisplay(updateBox);
5306
5307             if(guiApp.fullScreenMode)
5308             {
5309                guiApp.cursorUpdate = true;
5310                guiApp.PreserveAndDrawCursor();
5311             }
5312             if(guiApp.fullScreenMode)
5313                guiApp.RestoreCursorBackground();
5314             display.Unlock();
5315          }
5316       }
5317    }
5318
5319    // This function is strictly called as a result of system window activation
5320    bool ExternalActivate(bool active, bool activateRoot, Window window, Window swap)
5321    {
5322       bool result = true;
5323       Window interimMaster = null;
5324       Window interimWindow = guiApp.interimWindow;
5325       if(interimWindow && interimWindow.master)
5326          interimMaster = interimWindow.master.rootWindow;
5327
5328       if(active && state == minimized && window.parent) // && (!window.nativeDecorations || window.rootWindow != window)
5329          // SetState(normal, false, 0);
5330          SetState(lastState, false, 0);
5331
5332       if(interimMaster && swap == interimMaster && interimMaster.IsSlaveOf(window))
5333          return false;
5334
5335       incref this;
5336       /* WTH is this doing here?
5337       while(swap && swap.activeChild)
5338       {
5339          swap = swap.activeChild;
5340       }
5341       */
5342       // TESTING THIS BEFORE...
5343       if(interimWindow && this == interimMaster)
5344       {
5345          if(active)
5346          {
5347             // Window interimSwap = this;
5348             Window menuBar = this.menuBar;
5349             if(menuBar && interimWindow.master == menuBar)
5350             {
5351                /*
5352                while(interimSwap && interimSwap.activeChild)
5353                   interimSwap = interimSwap.activeChild;
5354
5355                result = interimWindow.ActivateEx(false, false, false, activateRoot, null,
5356                (menuBar && interimWindow.master == menuBar) ? menuBar : interimSwap);
5357                */
5358                result = /*interimWindow.*/ActivateEx(false, false, false, activateRoot, null, menuBar);
5359                //result = ActivateEx(true, true, false, activateRoot, window, null);
5360             }
5361          }
5362       }
5363       else
5364          // Testing & FindModal() here: broke reactivating when a modal dialog is up (didn't root activate dialog)
5365          result = ActivateEx(active, active, false, activateRoot /*&& FindModal()*/, window, swap);
5366
5367       if(interimWindow == this && interimMaster && !active)
5368       {
5369          while(interimMaster && interimMaster.interim && interimMaster.master)
5370          {
5371             // printf("Going up one master %s\n", interimMaster._class.name);
5372             interimMaster = interimMaster.master.rootWindow;
5373          }
5374          // printf("Unactivating interim master %s (%x)\n", interimMaster._class.name, interimMaster);
5375          interimMaster.ActivateEx(active, active, false, activateRoot, window, swap);
5376       }
5377       delete this;
5378       return result;
5379    }
5380
5381    bool DestroyEx(int64 returnCode)
5382    {
5383       OldLink slave;
5384       Timer timer, nextTimer;
5385       Window child;
5386       OldLink prevOrder = null;
5387       Window client = null;
5388
5389       if(parent) stopwatching(parent, font);
5390
5391       // if(window.modalSlave) return false;
5392       if(destroyed || !created)
5393       {
5394          if(master)
5395          {
5396             /*
5397             if(destroyed)
5398             {
5399                OldLink slave = master.slaves.FindLink(this);
5400                master.slaves.Delete(slave);
5401             }
5402             */
5403             // TOFIX IMMEDIATELY: COMMENTED THIS OUT... causes problem second time creating file dialog
5404             //master = null;
5405          }
5406          return true;
5407       }
5408
5409       this.returnCode = (DialogResult)returnCode;
5410
5411       AcquireInput(false);
5412
5413       destroyed = true;
5414       if(hotKey)
5415       {
5416          master.hotKeys.Delete(hotKey);
5417          hotKey = null;
5418       }
5419
5420       if(guiApp.prevWindow == this)
5421       {
5422          guiApp.prevWindow = null;
5423          OnMouseLeave(0);
5424       }
5425       if(guiApp.caretOwner == this)
5426       {
5427          guiApp.interfaceDriver.SetCaret(0,0,0);
5428          UpdateCaret(false, true);
5429          guiApp.caretEnabled = false;
5430       }
5431
5432       /*
5433       if(cycle)
5434          parent.childrenCycle.Remove(cycle);
5435       */
5436       if(order)
5437       {
5438          OldLink tmpPrev = order.prev;
5439          if(tmpPrev && !(((Window)tmpPrev.data).style.hidden) && !(((Window)tmpPrev.data).destroyed) && (((Window)tmpPrev.data).created))
5440             prevOrder = tmpPrev;
5441          for(;;)
5442          {
5443             client = tmpPrev ? tmpPrev.data : null;
5444             if(client == this) { client = null; break; }
5445             if(client && (client.style.hidden || client.destroyed || !client.created))
5446                tmpPrev = client.order.prev;
5447             else
5448             {
5449                if(client)
5450                   prevOrder = tmpPrev;
5451                break;
5452             }
5453          }
5454
5455          // If this window can be an active client, make sure the next window we activate can also be one
5456          if(!style.nonClient && style.isActiveClient)
5457          {
5458             tmpPrev = prevOrder;
5459             for(;;)
5460             {
5461                client = tmpPrev ? tmpPrev.data : null;
5462                if(client == this) { client = null; break; }
5463                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
5464                   tmpPrev = client.order.prev;
5465                else
5466                {
5467                   if(client)
5468                      prevOrder = tmpPrev;
5469                   break;
5470                }
5471             }
5472             if(client && client.style.hidden) client = null;
5473          }
5474          // parent.childrenOrder.Remove(order);
5475       }
5476
5477       if(parent && style.isActiveClient && visible)
5478       {
5479          if(state == minimized) parent.numIcons--;
5480          parent.numPositions--;
5481       }
5482
5483       // TESTING THIS HERE!
5484       created = false;
5485       visible = false;
5486
5487       // If no display, don't bother deactivating stuff (causes unneeded problems when trying
5488       // to create a window inside a rootwindow that's being destroyed)
5489       // DISABLED THIS BECAUSE OF CREATING WINDOW IN DESKTOP IN WINDOWED MODE
5490
5491       if(master && !master.destroyed /*&&
5492          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5493       {
5494          if(master.defaultControl == this)
5495             master.defaultControl = null;
5496       }
5497       if(parent)
5498          parent.OnChildAddedOrRemoved(this, true);
5499       if(parent && !parent.destroyed /*&&
5500          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5501       {
5502          if((parent.activeChild == this /*|| parent.activeClient == this */|| guiApp.interimWindow == this))
5503          {
5504             if(order && prevOrder && prevOrder.data != this && active)
5505             {
5506                //((Window)prevOrder.data).ActivateEx(true, false, false, false /*true*/, null);
5507
5508                ((Window)prevOrder.data).ActivateEx(true, false, false, (rootWindow == this) ? true : false, null, null);
5509                if(parent.activeClient == this)
5510                {
5511                   parent.activeClient = null;
5512                   parent.UpdateActiveDocument(null);
5513                }
5514             }
5515             else
5516             {
5517                if(guiApp.interimWindow == this)
5518                {
5519                   bool goOn = true;
5520                   PropagateActive(false, null, &goOn, true);
5521                }
5522                else
5523                {
5524                   //if(window.parent.activeChild == window)
5525                      parent.activeChild = null;
5526                   if(!style.nonClient /*&& style.isActiveClient*/)
5527                   {
5528                      Window previous = parent.activeClient;
5529                      if(style.isActiveClient)
5530                         parent.activeClient = null;
5531                      parent.UpdateActiveDocument(previous);
5532                   }
5533                }
5534             }
5535          }
5536          else if(parent.activeClient == this)
5537          {
5538             parent.activeClient = client;
5539             parent.UpdateActiveDocument(this);
5540
5541          }
5542       }
5543       if(guiApp.interimWindow == this)
5544       {
5545          guiApp.interimWindow = null;
5546          if(guiApp.caretOwner)
5547          {
5548             Window desktop = guiApp.desktop;
5549             if(desktop.activeChild && desktop.activeChild.menuBar && !desktop.activeChild.menuBar.focus)
5550                guiApp.caretOwner.UpdateCaret(false, false);
5551          }
5552       }
5553
5554       active = false;
5555       if(_isModal && master && master.modalSlave == this)
5556          master.modalSlave = null;
5557
5558       if(parent)
5559       {
5560          if(!guiApp.caretOwner && parent.caretSize)
5561          {
5562             guiApp.caretOwner = parent;
5563             parent.UpdateCaret(false, false);
5564             parent.Update(null);
5565          }
5566
5567          // Why was this commented out?
5568          GetRidOfVirtualArea();
5569       }
5570       /*
5571       delete cycle;
5572       delete order;
5573       */
5574       dirtyArea.Free(null);
5575       dirtyBack.Free(null);
5576       scrollExtent.Free(null);
5577
5578       /* ATTEMPTING TO MOVE THAT ABOVE
5579       created = false;
5580       visible = false;
5581       */
5582
5583       /*
5584       OnDestroy();
5585       {
5586          //Window next;
5587          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5588          for(;(child = window.children.first);)
5589          {
5590             for(; child && (child.destroyed || !child.created); child = child.next);
5591             if(child)
5592                child.DestroyEx(0);
5593             else
5594                break;
5595          }
5596       }
5597       */
5598
5599       UnloadGraphics(true);
5600
5601       if(previousActive)
5602          delete previousActive;
5603
5604       menuBar = null;
5605       // statusBar = null;
5606       sbv = sbh = null;
5607
5608       if(master && !master.destroyed)
5609       {
5610          //master.NotifyDestroyed(this, this.returnCode);
5611          NotifyDestroyed(master, this, this.returnCode);
5612       }
5613
5614       for(timer = guiApp.windowTimers.first; timer; timer = nextTimer)
5615       {
5616          nextTimer = timer.next;
5617          if(timer.window == this)
5618          {
5619             // WHY WERE WE SETTING THIS TO NULL? NO MORE WINDOW WHEN RECREATING...
5620             // timer.window = null;
5621             timer.Stop();
5622             //delete timer;
5623          }
5624       }
5625
5626       if(this == guiApp.windowMoving)
5627          StopMoving();
5628
5629       if(guiApp.windowCaptured == this)
5630          ReleaseCapture();
5631          //guiApp.windowCaptured = null;
5632
5633       if(rootWindow != this && rootWindow)
5634          rootWindow.ConsequentialMouseMove(false);
5635
5636       rootWindow = null;
5637
5638       OnDestroy();
5639
5640       {
5641          //Window next;
5642          //for(child = children.first; next = child ? child.next : null, child; child = next)
5643          for(;(child = children.first); )
5644          {
5645             for(; child && (child.destroyed || !child.created); child = child.next);
5646             if(child)
5647                child.DestroyEx(0);
5648             else
5649                break;
5650          }
5651       }
5652
5653       // master = null;
5654
5655       /* // MOVED THIS UP...
5656       {
5657          //Window next;
5658          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5659          for(;(child = window.children.first); )
5660          {
5661             for(; child && (child.destroyed || !child.created); child = child.next);
5662             if(child)
5663                child.DestroyEx(0);
5664             else
5665                break;
5666          }
5667       }
5668       */
5669
5670       while((slave = slaves.first))
5671       {
5672          for(; slave && (((Window)slave.data).destroyed || !((Window)slave.data).created); slave = slave.next);
5673          if(slave)
5674             ((Window)slave.data).DestroyEx(0);
5675          else
5676             break;
5677       }
5678
5679       if(guiApp.caretOwner == this)
5680          guiApp.caretOwner = null;
5681
5682       sysButtons[0] = null;
5683       sysButtons[1] = null;
5684       sysButtons[2] = null;
5685       activeChild = null;
5686
5687       if(rootWindow != this)
5688       {
5689          Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
5690          if(style.nonClient)
5691          {
5692             box.left   -= parent.clientStart.x;
5693             box.top    -= parent.clientStart.y;
5694             box.right  -= parent.clientStart.x;
5695             box.bottom -= parent.clientStart.y;
5696          }
5697          if(parent) parent.Update(box);
5698       }
5699       /*
5700       if(master)
5701       {
5702          OldLink slave = master.slaves.FindVoid(this);
5703          master.slaves.Delete(slave);
5704          master = null;
5705       }
5706
5707       if(parent)
5708       {
5709          parent.children.Remove(this);
5710          parent = null;
5711       }
5712       */
5713
5714       //autoCreate = false;
5715       //created = false;
5716
5717       // SHOULD THIS BE HERE? FIXED CRASH WITH GOTO DIALOG
5718       if(((subclass(Window))_class).pureVTbl)
5719       {
5720          if(_vTbl == _class._vTbl)
5721          {
5722             _vTbl = ((subclass(Window))_class).pureVTbl;
5723          }
5724          else
5725          {
5726             int m;
5727             for(m = 0; m < _class.vTblSize; m++)
5728             {
5729                if(_vTbl[m] == _class._vTbl[m])
5730                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5731             }
5732          }
5733       }
5734
5735       delete this;
5736       return true;
5737    }
5738
5739    void SetStateEx(WindowState newState, bool activate)
5740    {
5741       int x,y,w,h;
5742       WindowState prevState = state;
5743
5744       state = newState;
5745
5746       if(prevState != newState)
5747          lastState = prevState;
5748
5749       if(rootWindow != this || !nativeDecorations || !windowHandle)
5750       {
5751          if(style.isActiveClient && !style.hidden && prevState == minimized)
5752             parent.numIcons--;
5753
5754          // This block used to be at the end of the function... moved it for flicker problem in X
5755          // ------------------------------------------------------
5756          switch(state)
5757          {
5758             case normal:
5759                stateAnchor = normalAnchor;
5760                stateSizeAnchor = normalSizeAnchor;
5761                break;
5762             case maximized:
5763                stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5764                stateSizeAnchor = SizeAnchor {};
5765                break;
5766             case minimized:
5767             {
5768                int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5769                Window child;
5770                int size = 256;
5771                byte * idBuffer = new0 byte[size];
5772                int c;
5773                for(child = parent.children.first; child; child = child.next)
5774                {
5775                   if(child != this && child.state == minimized)
5776                   {
5777                      if(child.iconID > size - 2)
5778                      {
5779                         idBuffer = renew0 idBuffer byte[size*2];
5780                         memset(idBuffer + size, 0, size);
5781                         size *= 2;
5782                      }
5783                      idBuffer[child.iconID] = (byte)bool::true;
5784                   }
5785                }
5786                for(c = 0; c<size; c++)
5787                   if(!idBuffer[c])
5788                      break;
5789                iconID = c;
5790                delete idBuffer;
5791                if(style.isActiveClient && !style.hidden)
5792                   parent.numIcons++;
5793
5794                stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
5795                stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5796                break;
5797             }
5798          }
5799          // TOCHECK: Why was this here?
5800          //position.x = (tx > 0) ? tx & 0xFFFFF : tx;
5801          //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
5802          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5803
5804          Position(x, y, w, h, true, true, true, true, false, true);
5805
5806          if(!style.inactive && !style.interim && parent && this == parent.activeClient)
5807             parent.UpdateActiveDocument(null);
5808       }
5809
5810       CreateSystemChildren();
5811       // ------------------------------------------------------
5812    }
5813
5814    int GetPositionID(Window forChild)
5815    {
5816       Window child;
5817       int size = 256;
5818       byte * idBuffer = new0 byte[size];
5819       int c;
5820
5821       for(child = children.first; child; child = child.next)
5822       {
5823          if(child.style.isActiveClient && !child.style.hidden && child != forChild)
5824          {
5825             if(child.positionID > size - 2)
5826             {
5827                idBuffer = renew0 idBuffer byte[size*2];
5828                memset(idBuffer + size, 0, size);
5829                size *= 2;
5830             }
5831             idBuffer[child.positionID] = (byte)bool::true;
5832          }
5833       }
5834       for(c = 0; c<size; c++)
5835          if(!idBuffer[c])
5836             break;
5837       delete idBuffer;
5838       return c;
5839    }
5840
5841    // --- Window related graphics ---
5842
5843    void SetPalette(ColorAlpha * newPalette, bool colorMatch)
5844    {
5845       palette = newPalette;
5846       if(rootWindow.display)
5847          rootWindow.display.SetPalette(palette, colorMatch);
5848    }
5849
5850    public bool AcquireInput(bool acquired)
5851    {
5852       bool result = true;
5853       if(acquiredInput != acquired)
5854       {
5855          if(active || (!visible && creationActivation == activate))
5856             result = AcquireInputEx(acquired);
5857          /*if(!result)
5858          {
5859             Print("");
5860          }*/
5861          acquiredInput = acquired ? result : !result;
5862       }
5863       return result;
5864    }
5865
5866    void ListChildren(ListBox listBox)
5867    {
5868       Window child;
5869       char caption[2048];
5870       for(child = children.first; child; child = child.next)
5871       {
5872          if(child.cycle && !child.style.nonClient && child.style.isActiveClient && child.visible)
5873          {
5874             DataRow row = listBox.AddRow();
5875             row.tag = (int64)child;
5876             child.FigureCaption(caption);
5877             row.SetData(null, caption);
5878          }
5879       }
5880    }
5881
5882    void UpdateVisual(Box extent)
5883    {
5884       if(guiApp.driver != null)
5885       {
5886          if(guiApp.fullScreenMode && guiApp.desktop.display)
5887          {
5888             guiApp.desktop.mutex.Wait();
5889             guiApp.desktop.display.Lock(true);
5890
5891             Update(extent);
5892             if(guiApp.desktop.active)
5893             {
5894                if(guiApp.desktop.dirty || guiApp.cursorUpdate)
5895                {
5896                   if(guiApp.desktop.display.flags.flipping)
5897                      guiApp.desktop.Update(null);
5898                   guiApp.desktop.UpdateDisplay();
5899                   guiApp.cursorUpdate = true;
5900                }
5901                if(guiApp.cursorUpdate || guiApp.desktop.dirty)
5902                {
5903                   guiApp.PreserveAndDrawCursor();
5904                   // guiApp.desktop.display.ShowScreen();
5905                   guiApp.cursorUpdate = false;
5906                   guiApp.desktop.dirty = false;
5907                   guiApp.RestoreCursorBackground();
5908                }
5909             }
5910
5911             guiApp.desktop.display.Unlock();
5912             guiApp.desktop.mutex.Release();
5913          }
5914          else
5915          {
5916             Window rootWindow = this.rootWindow;
5917             rootWindow.mutex.Wait();
5918             display.Lock(true);
5919
5920             Update(extent);
5921             if(guiApp.waiting)
5922                guiApp.SignalEvent();
5923             else
5924             {
5925                guiApp.waitMutex.Wait();
5926                guiApp.interfaceDriver.Lock(rootWindow);
5927                if(!rootWindow.style.hidden && rootWindow.dirty)
5928                {
5929                   if(rootWindow.display)
5930                   {
5931                      rootWindow.UpdateDisplay();
5932                      //rootWindow.display.ShowScreen(null);
5933                   }
5934                   rootWindow.dirty = false;
5935                }
5936                guiApp.interfaceDriver.Unlock(rootWindow);
5937                guiApp.waitMutex.Release();
5938             }
5939             display.Unlock();
5940             rootWindow.mutex.Release();
5941          }
5942       }
5943    }
5944
5945    void UnlockDisplay(void)
5946    {
5947       guiApp.interfaceDriver.Unlock(rootWindow);
5948    }
5949
5950    void LockDisplay(void)
5951    {
5952       guiApp.interfaceDriver.Lock(rootWindow);
5953    }
5954
5955    Surface GetSurface(Box box)
5956    {
5957       return Redraw((box == null) ? this.box : box);
5958    }
5959
5960    void SetMousePosition(int x, int y)
5961    {
5962       guiApp.interfaceDriver.SetMousePosition(x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y);
5963    }
5964
5965    /*
5966    void IntegrationActivate(bool active)
5967    {
5968       if(!guiApp.modeSwitching && !guiApp.fullScreenMode)
5969       {
5970          isForegroundWindow = true;
5971          ActivateEx(active, active, false, false, null, null);
5972          isForegroundWindow = false;
5973       }
5974    }
5975    */
5976
5977    Window QueryCapture(void)
5978    {
5979       return guiApp.windowCaptured;
5980    }
5981
5982    int GetDocumentID(void)
5983    {
5984       Window child;
5985       int size = 256;
5986       byte * idBuffer = new0 byte[size];
5987       int c;
5988
5989       for(child = children.first; child; child = child.next)
5990       {
5991          // TO CHECK: Do we want a documentID when we already have a file name?
5992          if(child.style.isDocument && !child.fileName)
5993          {
5994             if(child.documentID-1 > size - 2)
5995             {
5996                idBuffer = renew0 idBuffer byte[size*2];
5997                memset(idBuffer + size, 0, size);
5998                size *= 2;
5999             }
6000             idBuffer[child.documentID-1] = 1;
6001          }
6002       }
6003       for(c = 0; c<size; c++)
6004          if(!idBuffer[c])
6005             break;
6006       numDocuments++;
6007       delete idBuffer;
6008       return c + 1;
6009    }
6010
6011    void SetInitSize(Size size)
6012    {
6013       int x, y, w, h;
6014       sizeAnchor.size = size;
6015       normalSizeAnchor = sizeAnchor;
6016
6017       // Break the anchors for moveable/resizable windows
6018       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6019       {
6020          stateAnchor = normalAnchor;
6021          stateSizeAnchor = normalSizeAnchor;
6022
6023          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6024          Position(x,y, w, h, true, true, true, true, false, true);
6025       }
6026    }
6027
6028    void MenuMoveOrSize(bool resize, bool setCursorPosition)
6029    {
6030       if(this != guiApp.desktop && state != maximized && (resize ? (state != minimized && style.sizable) : (style.fixed || moveable)))
6031       {
6032          guiApp.windowIsResizing = resize;
6033          guiApp.windowMoving = this;
6034          guiApp.windowMovingStart = guiApp.movingLast = absPosition;
6035          if(guiApp.windowIsResizing)
6036          {
6037             guiApp.windowMovingStart.x += size.w - 1;
6038             guiApp.windowMovingStart.y += size.h - 1;
6039          }
6040          guiApp.windowMovingBefore = scrolledPos;
6041          guiApp.windowResizingBefore = size;
6042          guiApp.windowMoving.UpdateDecorations();
6043          if(guiApp.windowIsResizing)
6044             guiApp.resizeEndX = guiApp.resizeEndY = true;
6045
6046          if(setCursorPosition)
6047             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
6048          else
6049          {
6050             int x, y;
6051             guiApp.interfaceDriver.GetMousePosition(&x, &y);
6052             guiApp.windowMovingStart.x += x - absPosition.x;
6053             guiApp.windowMovingStart.y += y - absPosition.y;
6054          }
6055
6056          if(guiApp.windowMoving)
6057          {
6058             if(guiApp.windowMoving.style.nonClient)
6059                guiApp.windowMoving.parent.SetMouseRangeToWindow();
6060             else
6061                guiApp.windowMoving.parent.SetMouseRangeToClient();
6062          }
6063
6064          Capture();
6065
6066          if(this == rootWindow)
6067             guiApp.interfaceDriver.StartMoving(rootWindow, guiApp.windowMovingStart.x, guiApp.windowMovingStart.y, true);
6068       }
6069    }
6070
6071 public:
6072    // normal Methods
6073    bool Create()
6074    {
6075       bool result = false;
6076
6077       if(created)
6078          result = true;
6079       else if(guiApp && guiApp.driver != null)
6080       {
6081          void * systemParent = null;
6082          OldLink slaveHolder;
6083          Window last;
6084          bool visible = !style.hidden;
6085
6086          if(style.embedded)
6087          {
6088             systemParent = parent;
6089             parent = guiApp.desktop;
6090          }
6091          last = parent ? parent.children.last : null;
6092
6093          if((parent && parent != guiApp.desktop && !parent.created) ||
6094             (master && master != guiApp.desktop && !master.created))
6095             return false;
6096
6097          if(parent)
6098             stopwatching(parent, font);
6099
6100          if(!parent)
6101             property::parent = guiApp.desktop;
6102          if(!master) master = parent;
6103
6104          if(_isModal && master.modalSlave)
6105             property::master = master.modalSlave;
6106             //return false;
6107
6108          if(parent)
6109             parent.children.Remove(this);
6110          if(master)
6111          {
6112             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
6113                if(slaveHolder.data == this)
6114                {
6115                   master.slaves.Delete(slaveHolder);
6116                   break;
6117                }
6118          }
6119
6120          if(parent == guiApp.desktop && !mutex)
6121             mutex = Mutex {};
6122
6123          if(style.isDocument)
6124          {
6125             if(parent)
6126                parent.numDocuments--;
6127             documentID = parent.GetDocumentID();
6128          }
6129
6130          if(!style.stayOnTop)
6131             for(; last && last.style.stayOnTop; last = last.prev);
6132
6133          parent.children.Insert((last == this) ? null : last, this);
6134          //parent.children.Add(this);
6135
6136          if(!dispDriver)
6137             dispDriver = parent.dispDriver;
6138          destroyed = false;
6139          if(_isModal)
6140             master.modalSlave = this;
6141
6142          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
6143
6144          incref this;
6145          incref this;
6146
6147          master.slaves.Add(slaveHolder = OldLink { data = this });
6148          if(slaveHolder)
6149          {
6150             if(setHotKey)
6151             {
6152                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
6153             }
6154             if(style.isDefault && !master.defaultControl)
6155                master.defaultControl = this;
6156
6157             stateAnchor = normalAnchor = anchor;
6158             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
6159
6160             // TOCHECK: Why is this here?
6161             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
6162             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
6163
6164             this.visible = false;
6165             style.hidden = true;
6166
6167             //created = true;
6168             // autoCreate = true;
6169             wasCreated = true;
6170             if(SetupDisplay())
6171             {
6172                created = true;
6173                if(OnCreate())
6174                {
6175                   /*
6176                   if(parent == guiApp.desktop)
6177                      Log("LoadGraphics %s\n", caption);
6178                   */
6179                   if(LoadGraphics(true, false))
6180                   {
6181                      if(!setFont)
6182                      {
6183                         watch(parent)
6184                         {
6185                            font
6186                            {
6187                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
6188                               firewatchers font;
6189                               Update(null);
6190                            }
6191                         };
6192                      }
6193
6194                      if(style.hasMenuBar /*&& menu*/)
6195                      {
6196                         menuBar =
6197                            PopupMenu
6198                            {
6199                               this,
6200                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
6201                               interim = false, inactive = true, nonClient = true, size.h = 24
6202                            };
6203                         menuBar.Create();
6204                      }
6205
6206                      if(statusBar)
6207                         statusBar.Create();
6208
6209                      // Create the system buttons
6210                      CreateSystemChildren();
6211
6212                      UpdateActiveDocument(null);
6213
6214                      if(style.isDocument)
6215                      {
6216                         if(menu)
6217                         {
6218                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6219                            if(item) item.disabled = !modifiedDocument && fileName;
6220                         }
6221                      }
6222
6223                      /*
6224                      if(parent == guiApp.desktop)
6225                         Log("Preemptive SetState %s\n", caption);
6226                      */
6227
6228                      // Preemptive Set State to ensure proper anchoring
6229                      SetStateEx(state, false);
6230                      /*
6231                      style.hidden = true;
6232                      visible = false;
6233                      */
6234
6235                      {
6236                         Window child, next;
6237                         for(child = children.first; child; child = next)
6238                         {
6239                            next = child.next;
6240                            if(!child.created && (child.autoCreate || child.wasCreated))
6241                               child.Create();
6242                         }
6243                      }
6244
6245                      {
6246                         OldLink link, next;
6247                         for(link = slaves.first; link; link = next)
6248                         {
6249                            Window slave = link.data;
6250                            next = link.next;
6251                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6252                            {
6253                               if(slave.Create())
6254                                  // Things might have happened that invalidated 'next'...
6255                                  // Start over the search for slaves to create.
6256                                  // (Added this to fix crash with Stacker & Toolbar)
6257                                  next = slaves.first;
6258                            }
6259                         }
6260                      }
6261
6262                      if(OnPostCreate())
6263                         OnApplyGraphics();
6264
6265                      /*
6266                      if(parent == guiApp.desktop)
6267                         Log("Real SetState %s\n", caption);
6268                      */
6269
6270                      if(isActiveClient && visible)
6271                      {
6272                         parent.numPositions--;
6273                         if(state == minimized) parent.numIcons--;
6274                      }
6275
6276                      parent.OnChildAddedOrRemoved(this, false);
6277
6278                      if(rootWindow == this && visible)   // So that X11 windows don't show as 'unknown'
6279                         UpdateCaption();
6280                      // Real set state & activate for proper display & activation
6281                      property::visible = visible;
6282                      //  SetState(state & 0x00000003, true, 0);
6283                      guiApp.interfaceDriver.SetIcon(this, icon);
6284
6285                      if(visible)
6286                      {
6287                         UpdateCaption();
6288                         /*if(rootWindow == this)
6289                            guiApp.interfaceDriver.ActivateRootWindow(this);
6290                         else*/
6291                         if(creationActivation == activate)
6292                            ActivateEx(true, false, true, true, null, null);
6293                         else if(creationActivation == flash)
6294                            Flash();
6295                      }
6296
6297                      if(!destroyed)
6298                         rootWindow.ConsequentialMouseMove(false);
6299
6300                      result = true;
6301                   }
6302                }
6303             }
6304          }
6305          /*
6306          if(!result)
6307          {
6308             Destroy(0);
6309             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6310          }
6311          */
6312
6313          if(!result)
6314          {
6315             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6316             created = false;
6317             //style.hidden = true; // !visible;
6318             style.hidden = !visible;
6319             if(master.modalSlave == this)
6320                master.modalSlave = null;
6321          }
6322          delete this;
6323       }
6324       return result;
6325    }
6326
6327    void WriteCaption(Surface surface, int x, int y)
6328    {
6329       if(caption)
6330          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6331    }
6332
6333    void Update(Box region)
6334    {
6335       if(this)
6336       {
6337          Window rootWindow;
6338
6339          rootWindow = this.rootWindow;
6340
6341          // rootWindow.mutex.Wait();
6342          if(!destroyed && visible && display)
6343          {
6344             Window child;
6345             Box realBox;
6346
6347             // Testing this to avoid repetitve full update to take time...
6348             if(dirtyArea.count == 1)
6349             {
6350                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6351                if(item.box.left <= box.left &&
6352                   item.box.top <= box.top &&
6353                   item.box.right >= box.right &&
6354                   item.box.bottom >= box.bottom)
6355                {
6356                   rootWindow.dirty = true;
6357                   return;
6358                }
6359             }
6360
6361             if(display.flags.flipping && !rootWindow.dirty)
6362             {
6363                if(this == rootWindow)
6364                   region = null;
6365                else
6366                {
6367                   rootWindow.Update(null);
6368                   return;
6369                }
6370             }
6371
6372             rootWindow.dirty = true;
6373
6374             if(region != null)
6375             {
6376                realBox = region;
6377                realBox.left += clientStart.x;
6378                realBox.top += clientStart.y;
6379                realBox.right += clientStart.x;
6380                realBox.bottom += clientStart.y;
6381                realBox.Clip(box);
6382             }
6383             else
6384                realBox = box;
6385
6386             if(realBox.right >= realBox.left &&
6387                realBox.bottom >= realBox.top)
6388             {
6389                // if(!rootWindow.fullRender)
6390                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6391
6392                for(child = children.first; child; child = child.next)
6393                {
6394                   if(!child.is3D)
6395                   {
6396                      Box box = realBox;
6397                      box.left -= child.absPosition.x - absPosition.x;
6398                      box.top -= child.absPosition.y - absPosition.y;
6399                      box.right -= child.absPosition.x - absPosition.x;
6400                      box.bottom -= child.absPosition.y - absPosition.y;
6401                      if(box.right >= child.box.left && box.left <= child.box.right &&
6402                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6403                      {
6404                         box.left -= child.clientStart.x;
6405                         box.top -= child.clientStart.y;
6406                         box.right -= child.clientStart.x;
6407                         box.bottom -= child.clientStart.y;
6408                         child.Update(box);
6409                      }
6410                   }
6411                }
6412
6413                realBox.left += absPosition.x - rootWindow.absPosition.x;
6414                realBox.top += absPosition.y - rootWindow.absPosition.y;
6415                realBox.right += absPosition.x - rootWindow.absPosition.x;
6416                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6417                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6418             }
6419          }
6420          else if(this == guiApp.desktop)
6421          {
6422             Window window;
6423             for(window = children.first; window; window = window.next)
6424             {
6425                if(!window.is3D)
6426                {
6427                   if(region != null)
6428                   {
6429                      Box childBox = region;
6430
6431                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6432                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6433                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6434                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6435
6436                      window.Update(childBox);
6437                   }
6438                   else
6439                      window.Update(null);
6440                }
6441             }
6442          }
6443
6444          // rootWindow.mutex.Release();
6445       }
6446    }
6447
6448    bool Capture(void)
6449    {
6450       bool result = true;
6451       if(guiApp.windowCaptured != this)
6452       {
6453          if(guiApp.windowCaptured)
6454             result = false;
6455          else
6456          {
6457             //Logf("Captured %s (%s)\n", caption, class.name);
6458             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6459             guiApp.windowCaptured = this;
6460          }
6461       }
6462       return result;
6463    }
6464
6465    bool Destroy(int64 code)
6466    {
6467       //if(created)
6468       if(this)
6469       {
6470          if(!destroyed && !CloseConfirmation(false)) return false;
6471          incref this;
6472          if(DestroyEx(code))
6473          {
6474             // TOCHECK: Should autoCreate be set to false here?
6475             autoCreate = false;
6476             wasCreated = false;
6477             delete this;
6478             return true;
6479          }
6480          delete this;
6481       }
6482       return false;
6483    }
6484
6485    void Move(int x, int y, int w, int h)
6486    {
6487       normalAnchor = Anchor { left = x, top = y };
6488       normalSizeAnchor = SizeAnchor { size = { w, h } };
6489
6490       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6491       {
6492          if(destroyed) return;
6493
6494          stateAnchor = normalAnchor;
6495          stateSizeAnchor = normalSizeAnchor;
6496
6497          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6498          Position(x,y, w, h, true, true, true, true, false, true);
6499       }
6500    }
6501
6502    DialogResult Modal(void)
6503    {
6504       isModal = true;
6505       if(Create())
6506          return DoModal();
6507
6508       // FIXES MEMORY LEAK IF Create() FAILED
6509       incref this;
6510       delete this;
6511       return 0;
6512    }
6513
6514    void SetScrollArea(int width, int height, bool snapToStep)
6515    {
6516       bool resize = false;
6517       if(snapToStep)
6518       {
6519          int stepX = sbStep.x, stepY = sbStep.y;
6520          // Needed to make snapped down position match the skin's check of client area
6521          // against realvirtual
6522          if(guiApp.textMode)
6523          {
6524             SNAPDOWN(stepX, textCellW);
6525             SNAPDOWN(stepY, textCellH);
6526             stepX = Max(stepX, textCellW);
6527             stepY = Max(stepY, textCellH);
6528          }
6529          if(scrollFlags.snapX)
6530             SNAPUP(width, stepX);
6531          if(scrollFlags.snapY)
6532             SNAPUP(height, stepY);
6533       }
6534
6535       reqScrollArea.w = width;
6536       reqScrollArea.h = height;
6537       noAutoScrollArea = (width > 0 || height > 0);
6538
6539       UpdateScrollBars(true, true);
6540    }
6541
6542    void SetScrollPosition(int x, int y)
6543    {
6544       if(sbh)
6545          sbh.Action(setPosition, x, 0);
6546       else
6547       {
6548          int range;
6549          int seen = clientSize.w, total = reqScrollArea.w;
6550          seen = Max(1,seen);
6551          if(scrollFlags.snapX)
6552             SNAPDOWN(seen, sbStep.x);
6553
6554          if(!total) total = seen;
6555          range = total - seen + 1;
6556          range = Max(range, 1);
6557          if(x < 0) x = 0;
6558          if(x >= range) x = range - 1;
6559
6560          if(scrollFlags.snapX)
6561             SNAPUP(x, sbStep.x);
6562
6563          if(scroll.x != x)
6564             OnHScroll(setPosition, x, 0);
6565
6566          if(guiApp.textMode)
6567          {
6568             SNAPDOWN(x, textCellW);
6569          }
6570          scroll.x = x;
6571       }
6572
6573       if(sbv)
6574          sbv.Action(setPosition, y, 0);
6575       else
6576       {
6577          int range;
6578          int seen = clientSize.h, total = reqScrollArea.h;
6579          seen = Max(1,seen);
6580
6581          if(scrollFlags.snapY)
6582             SNAPDOWN(seen, sbStep.y);
6583
6584          if(!total) total = seen;
6585          range = total - seen + 1;
6586          range = Max(range, 1);
6587          if(y < 0) y = 0;
6588          if(y >= range) y = range - 1;
6589
6590          if(scrollFlags.snapY)
6591             SNAPUP(y, sbStep.y);
6592
6593          if(scroll.y != y)
6594             OnVScroll(setPosition, y, 0);
6595          if(guiApp.textMode)
6596          {
6597             SNAPDOWN(y, textCellH);
6598          }
6599          scroll.y = y;
6600       }
6601       if(!sbh || !sbv)
6602          UpdateCaret(false, false);
6603    }
6604
6605    void SetScrollLineStep(int stepX, int stepY)
6606    {
6607       sbStep.x = stepX;
6608       sbStep.y = stepY;
6609       if(guiApp.textMode)
6610       {
6611          SNAPDOWN(stepX, textCellW);
6612          SNAPDOWN(stepY, textCellH);
6613          stepX = Max(stepX, textCellW);
6614          stepY = Max(stepY, textCellH);
6615       }
6616       if(sbh)
6617          sbh.lineStep = stepX;
6618       if(sbv)
6619          sbv.lineStep = stepY;
6620    }
6621
6622    void SetState(WindowState newState, bool activate, Modifiers mods)
6623    {
6624       if(created)
6625       {
6626          if(state == newState || OnStateChange(newState, mods))
6627          {
6628             WindowState prevState = state;
6629
6630             StopMoving();
6631
6632             // This used to be at the end of the brackets... moved for X, testing...
6633             // This has the effect of activating the window through the system...
6634             if(rootWindow == this)
6635                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6636
6637             SetStateEx(newState, activate);
6638
6639             if(rootWindow == this && !rootWindow.nativeDecorations)
6640             {
6641                int x = position.x, y = position.y;
6642                /*if(style.interim)
6643                {
6644                   x -= guiApp.desktop.absPosition.x;
6645                   y -= guiApp.desktop.absPosition.y;
6646                }*/
6647                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6648             }
6649
6650             //state = newState;
6651             //state = prevState;
6652
6653             if(state != maximized && style.hasMaximize)
6654             {
6655                Window child;
6656                for(child = parent.children.first; child; child = child.next)
6657                {
6658                   if(child != this && child.state == maximized)
6659                      child.SetStateEx(normal, false);
6660                }
6661             }
6662
6663             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6664                parent.UpdateScrollBars(true, true);
6665
6666             /*
6667             // Do we really need this stuff here?
6668             // Shouldn't the Activate stuff take care of it?
6669             if(parent.rootWindow == parent && style)
6670             {
6671                char caption[2048];
6672                parent.FigureCaption(caption);
6673                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6674                parent.UpdateDecorations();
6675             }
6676             */
6677
6678             rootWindow.ConsequentialMouseMove(false);
6679          }
6680       }
6681       else
6682          state = newState;
6683    }
6684
6685    BitmapResource GetIcon(SkinBitmap iconID)
6686    {
6687       return guiApp.currentSkin.GetBitmap(iconID);
6688    }
6689
6690    void SetMouseRange(Box range)
6691    {
6692       if(range || guiApp.fullScreenMode)
6693       {
6694          Box clip;
6695          if(range != null)
6696          {
6697             clip.left   = range.left + absPosition.x + clientStart.x;
6698             clip.top    = range.top + absPosition.y + clientStart.y;
6699             clip.right  = range.right + absPosition.x + clientStart.x;
6700             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6701          }
6702          else
6703          {
6704             clip.left   = guiApp.desktop.box.left;
6705             clip.top    = guiApp.desktop.box.top;
6706             clip.right  = guiApp.desktop.box.right;
6707             clip.bottom = guiApp.desktop.box.bottom;
6708          }
6709          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6710       }
6711       else
6712          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6713    }
6714
6715    void SetMouseRangeToClient(void)
6716    {
6717       if(guiApp.fullScreenMode || this != guiApp.desktop)
6718       {
6719          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6720          box.Clip(clientArea);
6721          SetMouseRange(box);
6722       }
6723       else
6724          SetMouseRange(null);
6725    }
6726
6727    void SetMouseRangeToWindow(void)
6728    {
6729       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6730       if(this == guiApp.desktop)
6731          SetMouseRangeToClient();
6732       else
6733          SetMouseRange(box);
6734    }
6735
6736    // x, y: Desktop Coordinates
6737    void ShowSysMenu(int x, int y)
6738    {
6739       Menu menu { };
6740       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6741       MenuItem
6742       {
6743          menu, $"Restore", r, NotifySelect = MenuWindowRestore,
6744          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6745       };
6746       MenuItem
6747       {
6748          menu, $"Move", m, NotifySelect = MenuWindowMove,
6749          disabled = !style.fixed || state == maximized
6750       };
6751       MenuItem
6752       {
6753          menu, $"Size", s, NotifySelect = MenuWindowSize,
6754          disabled = !style.sizable || state != normal
6755       };
6756       MenuItem
6757       {
6758          menu, $"Minimize", n, NotifySelect = MenuWindowMinimize,
6759          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6760       };
6761       MenuItem
6762       {
6763          menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize,
6764          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6765       };
6766       MenuItem
6767       {
6768          menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop,
6769          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6770       };
6771       MenuDivider { menu };
6772       MenuItem
6773       {
6774          menu, $"Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6775          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6776       };
6777       windowMenu.Create();
6778    }
6779
6780    void Activate(void)
6781    {
6782       ActivateEx(true, true, true, true, null, null);
6783    }
6784
6785    void MakeActive(void)
6786    {
6787       ActivateEx(true, false, true, false, null, null);
6788    }
6789
6790    void SoftActivate(void)
6791    {
6792       if(guiApp.desktop.active)
6793          Activate();
6794       else if(!active)
6795          Flash();
6796    }
6797
6798    void Deactivate(void)
6799    {
6800       ActivateEx(false, true, true, true, null, null);
6801    }
6802
6803    void Flash(void)
6804    {
6805       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6806    }
6807
6808    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6809    {
6810       bool result = false;
6811       if(activeChild && activeChild.cycle)
6812       {
6813          Window modalWindow, child = activeChild;
6814          if(!clientOnly /*&& parent.tabCycle*/)
6815          {
6816             Window next = child;
6817             while(true)
6818             {
6819                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6820                {
6821                   if(cycleParents)
6822                   {
6823                      if(parent && parent.CycleChildren(backward, false, true, true))
6824                         return true;
6825                      break;
6826                   }
6827                   else
6828                      return false;
6829                }
6830                if(backward)
6831                   next = next.cycle.prev.data;
6832                else
6833                   next = next.cycle.next.data;
6834                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6835                   break;
6836             }
6837          }
6838          /*
6839          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) &&
6840             parent.tabCycle && parent.CycleChildren(backward, false, false))
6841             return true;
6842          */
6843
6844          if(tabCycleOnly && !tabCycle) return false;
6845
6846          while(child)
6847          {
6848             while(true)
6849             {
6850                if(backward)
6851                   child = child.cycle.prev.data;
6852                else
6853                   child = child.cycle.next.data;
6854                if(child == child.parent.activeChild)
6855                   return result;
6856                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6857                   break;
6858             }
6859             modalWindow = child.FindModal();
6860             if(!modalWindow)
6861             {
6862                // Scroll the window to include the active control
6863                if(sbh && !child.style.dontScrollHorz)
6864                {
6865                   if(child.scrolledPos.x < 0)
6866                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6867                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6868                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6869                }
6870                if(sbv && !child.style.dontScrollVert)
6871                {
6872                   if(child.scrolledPos.y < 0)
6873                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6874                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6875                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6876                }
6877             }
6878             result = true;
6879             child = modalWindow ? modalWindow : child;
6880             child.ActivateEx(true, true, true, true, null, null);
6881             if(child.tabCycle && child.childrenCycle.first)
6882                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6883             else
6884                break;
6885          }
6886       }
6887       else
6888          return false;
6889
6890       ConsequentialMouseMove(false);
6891       return result;
6892    }
6893
6894    void AddResource(Resource resource)
6895    {
6896       if(resource)
6897       {
6898          ResPtr ptr { resource = resource };
6899          resources.Add(ptr);
6900          incref resource;
6901
6902          // Load Graphics here if window is created already
6903          if(/*created && */display)
6904          {
6905             display.Lock(false);
6906             ptr.loaded = display.displaySystem.LoadResource(resource);
6907             display.Unlock();
6908          }
6909          /*
6910          // Temporary hack to load font right away for listbox in dropbox ...
6911          else if(master && master.display)
6912          {
6913             master.display.Lock(false);
6914             master.display.displaySystem.LoadResource(resource);
6915             master.display.Unlock();
6916          }
6917          */
6918       }
6919    }
6920
6921    void RemoveResource(Resource resource)
6922    {
6923       if(resource)
6924       {
6925          ResPtr ptr;
6926          for(ptr = resources.first; ptr; ptr = ptr.next)
6927          {
6928             if(ptr.resource == resource)
6929                break;
6930          }
6931
6932          if(ptr)
6933          {
6934             // Unload Graphics here if window is created already
6935             if(/*created && */display)
6936             {
6937                if(ptr.loaded)
6938                {
6939                   display.Lock(false);
6940                   display.displaySystem.UnloadResource(resource, ptr.loaded);
6941                   display.Unlock();
6942                   ptr.loaded = null;
6943                }
6944             }
6945             delete resource;
6946             resources.Delete(ptr);
6947          }
6948       }
6949    }
6950
6951    void SetCaret(int x, int y, int size)
6952    {
6953       if(!destroyed)
6954       {
6955          caretPos.x = x;
6956          caretPos.y = y;
6957          caretSize = size;
6958          if(active && !style.interim && isEnabled)
6959          {
6960             if(visible || !guiApp.caretOwner)
6961                guiApp.caretOwner = size ? this : null;
6962             if(size)
6963                UpdateCaret(false, false);
6964             else
6965             {
6966                guiApp.interfaceDriver.SetCaret(0,0,0);
6967                UpdateCaret(false, true);
6968                guiApp.caretEnabled = false;
6969             }
6970          }
6971          else if(style.inactive && active)
6972          {
6973             guiApp.interfaceDriver.SetCaret(0,0,0);
6974             UpdateCaret(false, true);
6975             guiApp.caretEnabled = false;
6976          }
6977       }
6978    }
6979
6980    void Scroll(int x, int y)
6981    {
6982       bool opaque = !style.drawBehind || background.a;
6983       if(opaque && display && display.flags.scrolling)
6984       {
6985          Box box = clientArea;
6986          box.left += clientStart.x;
6987          box.top += clientStart.y;
6988          box.right += clientStart.x;
6989          box.bottom += clientStart.y;
6990
6991          //scrollExtent.Free(null);
6992          scrollExtent.AddBox(box);
6993          scrolledArea.x += x;
6994          scrolledArea.y += y;
6995
6996          //scrollExtent.Free();
6997          //scrollExtent.AddBox(clientArea);
6998          //scrollExtent.Offset(clientStart.x, clientStart.y);
6999          //scrolledArea.x = x;
7000          //scrolledArea.y = y;
7001       }
7002       else
7003          Update(clientArea);
7004
7005       if(rootWindow)
7006          rootWindow.dirty = true;
7007    }
7008
7009    void ReleaseCapture()
7010    {
7011       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
7012       {
7013          Window oldCaptured = guiApp.windowCaptured;
7014          guiApp.windowCaptured = null;
7015          guiApp.prevWindow = null;
7016          incref oldCaptured;
7017
7018          //guiApp.Log("Released Capture\n");
7019
7020          guiApp.interfaceDriver.SetMouseCapture(null);
7021
7022          //oldCaptured.OnMouseCaptureLost();
7023
7024          if(oldCaptured)
7025             oldCaptured.ConsequentialMouseMove(false);
7026          delete oldCaptured;
7027       }
7028    }
7029
7030    private void _SetCaption(char * format, va_list args)
7031    {
7032       if(this)
7033       {
7034          delete caption;
7035          if(format)
7036          {
7037             char caption[MAX_F_STRING];
7038             vsnprintf(caption, sizeof(caption), format, args);
7039             caption[sizeof(caption)-1] = 0;
7040
7041             this.caption = CopyString(caption);
7042          }
7043          if(created)
7044             UpdateCaption();
7045
7046          firewatchers caption;
7047       }
7048    }
7049
7050    /*deprecated*/ void SetText(char * format, ...)
7051    {
7052       va_list args;
7053       va_start(args, format);
7054       _SetCaption(format, args);
7055       va_end(args);
7056    }
7057
7058    void SetCaption(char * format, ...)
7059    {
7060       va_list args;
7061       va_start(args, format);
7062       _SetCaption(format, args);
7063       va_end(args);
7064    }
7065
7066    bool Grab(Bitmap bitmap, Box box, bool decorations)
7067    {
7068       bool result = false;
7069       if(display || this == guiApp.desktop)
7070       {
7071          Box clip = {MININT, MININT, MAXINT, MAXINT};
7072
7073          if(box != null)
7074             clip = box;
7075
7076          if(!decorations)
7077             clip.Clip(clientArea);
7078          else
7079             clip.Clip(this.box);
7080
7081          if(rootWindow != this)
7082          {
7083             clip.left   += absPosition.y;
7084             clip.top    += absPosition.y;
7085             clip.right  += absPosition.x;
7086             clip.bottom += absPosition.y;
7087          }
7088
7089          clip.left += decorations ? 0 : clientStart.x;
7090          clip.top += decorations ? 0 : clientStart.y;
7091          clip.right += decorations ? 0 : clientStart.x;
7092          clip.bottom += decorations ? 0 : clientStart.y;
7093
7094          if(display && display.flags.flipping)
7095          {
7096             rootWindow.Update(null);
7097             rootWindow.UpdateDisplay();
7098          }
7099
7100          if(!display)
7101          {
7102             Window window { };
7103             window.Create();
7104             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top,
7105                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7106             delete window;
7107          }
7108          else
7109             result = display.Grab(bitmap, clip.left, clip.top,
7110                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7111
7112          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7113          {
7114             if(!bitmap.Convert(null, pixelFormat888, null))
7115                result = false;
7116          }
7117       }
7118       return result;
7119    }
7120
7121    void GetMousePosition(int * x, int * y)
7122    {
7123       int mouseX = 0, mouseY = 0;
7124       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7125       {
7126          if(guiApp.driver)
7127             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7128          if(this != guiApp.desktop)
7129          {
7130             mouseX -= absPosition.x + clientStart.x;
7131             mouseY -= absPosition.y + clientStart.y;
7132          }
7133       }
7134       if(x) *x = mouseX;
7135       if(y) *y = mouseY;
7136    }
7137
7138    DialogResult DoModal()
7139    {
7140       DialogResult returnCode = 0;
7141       int terminated = terminateX;
7142       isModal = true;
7143       incref this;
7144       while(!destroyed && guiApp.driver != null)
7145       {
7146          if(terminateX != terminated)
7147          {
7148             terminated = terminateX;
7149             guiApp.desktop.Destroy(0);
7150             if(guiApp.desktop.created)
7151             {
7152                terminated = 0;
7153                //printf("Resetting terminate X to 0\n");
7154                terminateX = 0;
7155             }
7156             break;
7157          }
7158
7159          guiApp.UpdateDisplay();
7160          if(!guiApp.ProcessInput(false))
7161             guiApp.Wait();
7162       }
7163       returnCode = this.returnCode;
7164       delete this;
7165       return returnCode;
7166    }
7167
7168    void DoModalStart()
7169    {
7170       isModal = true;
7171       incref this;
7172    }
7173
7174    bool DoModalLoop()
7175    {
7176       return !destroyed && guiApp.driver != null && terminateX < 2;
7177    }
7178
7179    DialogResult DoModalEnd()
7180    {
7181       DialogResult returnCode = this.returnCode;
7182       delete this;
7183       return returnCode;
7184    }
7185
7186    // --- Window manipulation ---
7187    /*bool GetDisabled()
7188    {
7189       bool disabled = this.disabled;
7190       Window window;
7191       for(window = this; (window = window.master); )
7192       {
7193          if(window.disabled)
7194          {
7195             disabled = true;
7196             break;
7197          }
7198       }
7199       return disabled;
7200    }*/
7201
7202    // --- Mouse Manipulation ---
7203    void GetNCMousePosition(int * x, int * y)
7204    {
7205       GetMousePosition(x, y);
7206       if(x) *x += clientStart.x;
7207       if(y) *y += clientStart.y;
7208    }
7209
7210    // --- Carets manipulation ---
7211    void GetCaretPosition(Point caretPos)
7212    {
7213       caretPos = this.caretPos;
7214    }
7215
7216    int GetCaretSize(void)
7217    {
7218       return caretSize;
7219    }
7220
7221    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7222    {
7223       Destroy(button.id);
7224       return true;
7225    }
7226
7227    bool CloseConfirmation(bool parentClosing)
7228    {
7229       bool result = true;
7230       OldLink slave;
7231       Window child;
7232
7233       if(closing)
7234          return false;
7235       if(terminateX > 1)
7236          return true;
7237
7238       closing = true;
7239
7240       if(!OnClose(parentClosing))
7241          result = false;
7242
7243       // If you want to skip this, simply set modifiedDocument to false in OnClose
7244       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7245       {
7246          DialogResult dialogRes;
7247          char message[1024];
7248          if(fileName)
7249             sprintf(message, $"Save changes to %s?", fileName);
7250          else
7251             sprintf(message, $"Save changes to Untitled %d?", documentID);
7252
7253          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7254
7255          if(dialogRes == yes)
7256          {
7257             // TOFIX: Precomp error if brackets are taken out
7258             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7259          }
7260          else if(dialogRes == cancel)
7261             result = false;
7262       }
7263
7264       if(result)
7265       {
7266          for(slave = slaves.first; slave; slave = slave.next)
7267          {
7268             Window w = slave.data;
7269             if((w.parent == this || !w.IsDescendantOf(this)) && !w.CloseConfirmation(true))
7270             {
7271                // ((Window)slave.data).CloseConfirmation(true);
7272                result = false;
7273                break;
7274             }
7275          }
7276       }
7277
7278       if(result)
7279       {
7280          for(child = children.first; child; child = child.next)
7281             if(child.master != this && !child.CloseConfirmation(true))
7282             {
7283                result = false;
7284                break;
7285             }
7286       }
7287       closing = false;
7288       return result;
7289    }
7290
7291    // Static methods... move them somewhere else?
7292    void ::RestoreCaret()
7293    {
7294       if(guiApp.caretOwner)
7295          guiApp.caretOwner.UpdateCaret(false, false);
7296    }
7297
7298    void ::FreeMouseRange()
7299    {
7300       guiApp.interfaceDriver.SetMouseRange(null, null);
7301    }
7302
7303    // Menu Methods
7304    bool MenuFileClose(MenuItem selection, Modifiers mods)
7305    {
7306       Window document = activeChild;
7307       if(document)
7308          document.Destroy(0);
7309       return true;
7310    }
7311
7312    bool MenuFileExit(MenuItem selection, Modifiers mods)
7313    {
7314       Destroy(0);
7315       return true;
7316    }
7317
7318    bool MenuFileSave(MenuItem selection, Modifiers mods)
7319    {
7320       if(fileName)
7321       {
7322          fileMonitor.fileName = null;
7323          saving = true;
7324
7325          if(OnSaveFile(fileName))
7326          {
7327             //if(OnFileModified != Window::OnFileModified)
7328             {
7329                saving = false;
7330                fileMonitor.fileName = fileName;
7331             }
7332             return true;
7333          }
7334          else
7335          {
7336             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7337             DialogResult answer = dialog.Modal();
7338             saving = false;
7339             if(answer != yes) return (bool)answer;
7340          }
7341       }
7342       return MenuFileSaveAs(selection, mods);
7343    }
7344
7345    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7346    {
7347       DialogResult result = (DialogResult)bool::true;
7348       FileDialog fileDialog = saveDialog;
7349
7350       if(!fileDialog)
7351          fileDialog = FileDialog {};
7352       if(fileDialog)
7353       {
7354          incref fileDialog;
7355          if(fileName)
7356             fileDialog.filePath = fileName;
7357          else
7358          {
7359             char filePath[MAX_FILENAME];
7360             sprintf(filePath, "Untitled %d", documentID);
7361             fileDialog.filePath = filePath;
7362          }
7363          fileMonitor.fileName = null;
7364
7365          fileDialog.type = save;
7366          fileDialog.text = $"Save As";
7367
7368          while(true)
7369          {
7370             fileDialog.master = master.parent ? master : this;
7371             if(fileDialog.Modal() == ok)
7372             {
7373                char * filePath = fileDialog.filePath;
7374                saving = true;
7375                if(OnSaveFile(filePath))
7376                {
7377                   saving = false;
7378                   property::fileName = filePath;
7379                   NotifySaved(master, this, filePath);
7380                   break;
7381                }
7382                else
7383                {
7384                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7385                   DialogResult answer = dialog.Modal();
7386                   saving = false;
7387                   if(answer != yes)
7388                   {
7389                      result = answer;
7390                      break;
7391                   }
7392                }
7393             }
7394             else
7395             {
7396                result = cancel;
7397                break;
7398             }
7399          }
7400          //if(OnFileModified != Window::OnFileModified && fileName)
7401          {
7402             if(fileName)
7403                fileMonitor.fileName = fileName;
7404          }
7405          delete fileDialog;
7406       }
7407       return (bool)result; // Actually returning result from Yes/NoCancel message box
7408    }
7409
7410    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7411    {
7412       Window document = activeChild;
7413       Window next;
7414       for(document = children.first; document; document = next)
7415       {
7416          next = document.next;
7417          if(document.style.isDocument || document.fileName)
7418             document.MenuFileSave(selection, mods);
7419       }
7420       return true;
7421    }
7422
7423    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7424    {
7425       Window document;
7426
7427       for(document = children.first; document; document = document.next)
7428          //if(document.style.isDocument && document.state == minimized)
7429          if(document.style.isActiveClient && document.state == minimized)
7430             document.SetState(minimized, false, mods);
7431       return true;
7432    }
7433
7434    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7435    {
7436       Window document = activeChild;
7437       if(document)
7438       {
7439          Window firstDocument = null;
7440          Window child;
7441          OldLink cycle = document.cycle.prev;
7442          int id = 0;
7443          while(true)
7444          {
7445             child = cycle.data;
7446             if(child.style.isActiveClient && !child.style.hidden)
7447             {
7448                Window last;
7449
7450                firstDocument = child;
7451                if(child.state == minimized)
7452                   child.SetState(minimized, false, mods);
7453                else
7454                {
7455                   child.positionID = id++;
7456                   child.SetState(normal, false, mods);
7457                   child.anchor.left.type = cascade;
7458                   {
7459                      int x, y, w, h;
7460                      child.normalSizeAnchor = *&child.sizeAnchor;
7461                      child.normalAnchor = child.anchor;
7462
7463                      // Break the anchors for moveable/resizable windows
7464                      if(child.style.fixed)
7465                      {
7466                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7467
7468                         (*&child.normalAnchor).left = x;
7469                         (*&child.normalAnchor).top = y;
7470                         (*&child.normalAnchor).right.type = none;
7471                         (*&child.normalAnchor).bottom.type = none;
7472
7473                         child.normalSizeAnchor.isClientW = false;
7474                         child.normalSizeAnchor.isClientH = false;
7475                         child.normalSizeAnchor.size.w = w;
7476                         child.normalSizeAnchor.size.h = h;
7477                         child.anchored = false;
7478                      }
7479
7480                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7481                      {
7482                         child.stateAnchor = child.normalAnchor;
7483                         child.stateSizeAnchor = child.normalSizeAnchor;
7484
7485                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7486                         child.Position(x, y, w, h, true, true, true, true, false, false);
7487                      }
7488                   }
7489                }
7490
7491                last = children.last;
7492                if(!child.style.stayOnTop)
7493                   for(; last && last.style.stayOnTop; last = last.prev);
7494                children.Move(child, last);
7495                childrenOrder.Move(child.order, childrenOrder.last);
7496             }
7497             if(cycle == document.cycle) break;
7498             cycle = cycle.prev;
7499          }
7500          if(firstDocument)
7501             firstDocument.Activate();
7502       }
7503       return true;
7504    }
7505
7506    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7507    {
7508       if(style.hasClose)
7509          Destroy(0);
7510       return true;
7511    }
7512
7513    // Close all closes all active clients, not all documents
7514    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7515    {
7516       Window next, document;
7517
7518       for(document = children.first; document; document = next)
7519       {
7520          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7521          if(document.style.isActiveClient)
7522             if(!document.Destroy(0) && !document.style.hidden)
7523                return false;
7524       }
7525       return true;
7526    }
7527
7528    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7529    {
7530       if(style.hasMaximize && state != maximized)
7531          SetState(maximized, 0, 0);
7532       return true;
7533    }
7534
7535    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7536    {
7537       if(style.hasMinimize && state != minimized)
7538       {
7539          SetState(minimized, 0, 0);
7540          parent.CycleChildren(false, true, false, true);
7541       }
7542       return true;
7543    }
7544
7545    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7546    {
7547       MenuMoveOrSize(false, selection ? true : false);
7548       return true;
7549    }
7550
7551    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7552    {
7553       CycleChildren(false, true, false, true);
7554       return true;
7555    }
7556
7557    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7558    {
7559       CycleChildren(true, true, false, true);
7560       return true;
7561    }
7562
7563    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7564    {
7565       MenuMoveOrSize(true, true);
7566       return true;
7567    }
7568
7569    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7570    {
7571       if(state != normal)
7572          SetState(normal, 0, 0);
7573       return true;
7574    }
7575
7576    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7577    {
7578       Window document;
7579       int64 id = selection.id;
7580       OldLink cycle = activeClient.cycle;
7581       int c = 0;
7582       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7583       while(true)
7584       {
7585          Window sibling = cycle.data;
7586          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7587          {
7588             if(c == id)
7589                break;
7590             c++;
7591          }
7592          cycle = cycle.next;
7593       }
7594       document = cycle.data;
7595       document.Activate();
7596
7597       //if(activeChild.state == maximized)
7598       //  document.SetState(maximized, false, mods);
7599       //else if(document.state == minimized)
7600       //   document.SetState(normal, false, mods);
7601       return true;
7602    }
7603
7604    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7605    {
7606       stayOnTop = !style.stayOnTop;
7607       return true;
7608    }
7609
7610    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7611    {
7612       Window document = activeChild;
7613       if(document)
7614       {
7615          Window firstDocument = null;
7616          OldLink cycle = document.cycle;
7617          int id = 0;
7618          while(true)
7619          {
7620             Window child = cycle.data;
7621             if(child.style.isActiveClient && !child.style.hidden)
7622             {
7623                if(!firstDocument) firstDocument = child;
7624                if(child.state == minimized)
7625                   child.SetState(minimized, false, mods);
7626                else
7627                {
7628                   child.positionID = id++;
7629                   child.SetState(normal, false, mods);
7630                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7631
7632                   child.anchor.left.type = hTiled;
7633                   {
7634                      int x, y, w, h;
7635                      child.normalSizeAnchor = *&child.sizeAnchor;
7636                      child.normalAnchor = child.anchor;
7637
7638                      // Break the anchors for moveable/resizable windows
7639                      if(child.style.fixed)
7640                      {
7641                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7642
7643                         (*&child.normalAnchor).left = x;
7644                         (*&child.normalAnchor).top = y;
7645                         (*&child.normalAnchor).right.type = none;
7646                         (*&child.normalAnchor).bottom.type = none;
7647                         child.normalSizeAnchor.isClientW = false;
7648                         child.normalSizeAnchor.isClientH = false;
7649                         child.normalSizeAnchor.size.w = w;
7650                         child.normalSizeAnchor.size.h = h;
7651                         child.anchored = false;
7652                      }
7653
7654                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7655                      {
7656                         child.stateAnchor = child.normalAnchor;
7657                         child.stateSizeAnchor = child.normalSizeAnchor;
7658
7659                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7660                         child.Position(x,y, w, h, true, true, true, true, false, true);
7661                      }
7662                   }
7663                }
7664             }
7665             if((cycle = cycle.next) == document.cycle) break;
7666          }
7667          if(firstDocument)
7668             firstDocument.Activate();
7669       }
7670       return true;
7671    }
7672
7673    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7674    {
7675       Window document = activeChild;
7676       if(document)
7677       {
7678          Window firstDocument = null;
7679          Window child;
7680          OldLink cycle = document.cycle;
7681          int id = 0;
7682          while(true)
7683          {
7684             child = cycle.data;
7685             //if(child.style.isDocument)
7686             if(child.style.isActiveClient && !child.style.hidden)
7687             {
7688                if(!firstDocument) firstDocument = child;
7689                if(child.state == minimized)
7690                   child.SetState(minimized, false, mods);
7691                else
7692                {
7693                   child.positionID = id++;
7694                   child.SetState(normal, false, mods);
7695                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7696
7697                   child.anchor.left.type = vTiled;
7698                   {
7699                      int x, y, w, h;
7700                      child.normalSizeAnchor = *&child.sizeAnchor;
7701                      child.normalAnchor = child.anchor;
7702
7703                      // Break the anchors for moveable/resizable windows
7704                      if(child.style.fixed)
7705                      {
7706                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7707
7708                         (*&child.normalAnchor).left = x;
7709                         (*&child.normalAnchor).top = y;
7710                         (*&child.normalAnchor).right.type = none;
7711                         (*&child.normalAnchor).bottom.type = none;
7712                         child.normalSizeAnchor.isClientW = false;
7713                         child.normalSizeAnchor.isClientH = false;
7714                         child.normalSizeAnchor.size.w = w;
7715                         child.normalSizeAnchor.size.h = h;
7716                         child.anchored = false;
7717                      }
7718
7719                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7720                      {
7721                         child.stateAnchor = child.normalAnchor;
7722                         child.stateSizeAnchor = child.normalSizeAnchor;
7723
7724                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7725                         child.Position(x,y, w, h, true, true, true, true, false, true);
7726                      }
7727                   }
7728                }
7729             }
7730             if((cycle = cycle.next) == document.cycle) break;
7731          }
7732          if(firstDocument)
7733             firstDocument.Activate();
7734       }
7735       return true;
7736    }
7737
7738    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7739    {
7740       WindowList dialog { master = this };
7741       Window document = (Window)dialog.Modal();
7742       if(document)
7743       {
7744          if(activeChild.state == maximized)
7745             document.SetState(maximized, false, mods);
7746          else if(document.state == minimized)
7747             document.SetState(normal, false, mods);
7748          document.Activate();
7749       }
7750       return true;
7751    }
7752
7753    // Virtual Methods
7754    virtual bool OnCreate(void);
7755    virtual void OnDestroy(void);
7756    virtual void OnDestroyed(void);
7757    virtual bool OnClose(bool parentClosing);
7758    virtual bool OnStateChange(WindowState state, Modifiers mods);
7759    virtual bool OnPostCreate(void);
7760    virtual bool OnMoving(int *x, int *y, int w, int h);
7761    virtual bool OnResizing(int *width, int *height);
7762    virtual void OnResize(int width, int height);
7763    virtual void OnPosition(int x, int y, int width, int height);
7764    virtual bool OnLoadGraphics(void);
7765    virtual void OnApplyGraphics(void);
7766    virtual void OnUnloadGraphics(void);
7767    virtual void OnRedraw(Surface surface);
7768    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7769    virtual void OnActivateClient(Window client, Window previous);
7770    virtual bool OnKeyDown(Key key, unichar ch);
7771    virtual bool OnKeyUp(Key key, unichar ch);
7772    virtual bool OnKeyHit(Key key, unichar ch);
7773    virtual bool OnSysKeyDown(Key key, unichar ch);
7774    virtual bool OnSysKeyUp(Key key, unichar ch);
7775    virtual bool OnSysKeyHit(Key key, unichar ch);
7776    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7777    virtual bool OnMouseLeave(Modifiers mods);
7778    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7779    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7780    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7781    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7782    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7783    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7784    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7785    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7786    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7787    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7788    virtual void OnMouseCaptureLost(void);
7789    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7790    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7791    virtual void OnDrawOverChildren(Surface surface);
7792    virtual bool OnFileModified(FileChange fileChange, char * param);
7793    virtual bool OnSaveFile(char * fileName);
7794
7795    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
7796    // Note: A 'client' would refer to isActiveClient, rather than
7797    // being confined to the 'client area' (nonClient == false)
7798    virtual void OnChildAddedOrRemoved(Window child, bool removed);
7799    virtual void OnChildVisibilityToggled(Window child, bool visible);
7800    virtual void OnChildResized(Window child, int x, int y, int w, int h);
7801
7802    // Skins Virtual Functions
7803    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7804    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7805    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7806    {
7807       *cw = *w;
7808       *ch = *h;
7809    }
7810    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7811    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7812    virtual bool IsMouseMoving(int x, int y, int w, int h)
7813    {
7814       return false;
7815    }
7816    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
7817    {
7818       return false;
7819    }
7820    virtual void UpdateNonClient();
7821    virtual void SetBox(Box box);    // This is used in the MySkin skin
7822    virtual bool IsInside(int x, int y)
7823    {
7824       return box.IsPointInside({x, y});
7825    }
7826    virtual bool IsOpaque()
7827    {
7828       return (!style.drawBehind || background.a == 255);
7829    }
7830
7831    // Notifications
7832    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7833    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7834    virtual void Window::NotifySaved(Window window, char * filePath);
7835
7836    // Public Methods
7837
7838    // Properties
7839    property Window parent
7840    {
7841       property_category $"Layout"
7842       set
7843       {
7844          if(value || guiApp.desktop)
7845          {
7846             Window last;
7847             Window oldParent = parent;
7848             Anchor anchor = this.anchor;
7849
7850             if(value && value.IsDescendantOf(this)) return;
7851             if(value && value == this)
7852                return;
7853             if(!value) value = guiApp.desktop;
7854
7855             if(value == oldParent) return;
7856
7857             if(!master || (master == this.parent && master == guiApp.desktop))
7858                property::master = value;
7859
7860             if(parent)
7861             {
7862                parent.children.Remove(this);
7863
7864                parent.Update(
7865                {
7866                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7867                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7868                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7869                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7870                });
7871             }
7872
7873             last = value.children.last;
7874
7875             if(style.isDocument)
7876             {
7877                if(parent)
7878                   parent.numDocuments--;
7879                documentID = value.GetDocumentID();
7880             }
7881
7882             if(style.isActiveClient && !style.hidden)
7883             {
7884                if(parent && parent != guiApp.desktop && !(style.hidden))
7885                {
7886                   if(state == minimized) parent.numIcons--;
7887                   parent.numPositions--;
7888                }
7889             }
7890
7891             if(!style.stayOnTop)
7892                for(; last && last.style.stayOnTop; last = last.prev);
7893
7894             value.children.Insert(last, this);
7895
7896             // *** NEW HERE: ***
7897             if(cycle)
7898                parent.childrenCycle.Delete(cycle);
7899             if(order)
7900                parent.childrenOrder.Delete(order);
7901             cycle = null;
7902             order = null;
7903             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
7904             //           Should something else be done?
7905             if(parent && parent.activeChild == this)
7906                parent.activeChild = null;
7907             if(parent && parent.activeClient == this)
7908                parent.activeClient = null;
7909
7910             //if(created)
7911             {
7912                if(created)
7913                {
7914                   int x = position.x, y = position.y, w = size.w, h = size.h;
7915
7916                   int vpw, vph;
7917
7918                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7919                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7920
7921                   vpw = value.clientSize.w;
7922                   vph = value.clientSize.h;
7923                   if(style.nonClient)
7924                   {
7925                      vpw = value.size.w;
7926                      vph = value.size.h;
7927                   }
7928                   else if(style.fixed)
7929                   {
7930                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7931                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7932                   }
7933
7934                   anchor = this.anchor;
7935
7936                   if(anchor.left.type == offset)            anchor.left.distance = x;
7937                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7938                   if(anchor.top.type == offset)             anchor.top.distance = y;
7939                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7940                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7941                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7942                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7943                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7944                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7945                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7946
7947                   if(!anchor.left.type && !anchor.right.type)
7948                   {
7949                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7950                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7951                   }
7952                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7953                   if(!anchor.top.type && !anchor.bottom.type)
7954                   {
7955                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7956                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7957                   }
7958                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7959                }
7960                parent = value;
7961                parent.OnChildAddedOrRemoved(this, false);
7962
7963                // *** NEW HERE ***
7964                if(!style.inactive)
7965                {
7966                   if(!style.noCycle)
7967                      parent.childrenCycle.Insert(
7968                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
7969                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
7970                         null,
7971                         cycle = OldLink { data = this });
7972                   parent.childrenOrder.Insert(
7973                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
7974                      order = OldLink { data = this });
7975                }
7976
7977                if(!style.hidden && style.isActiveClient)
7978                {
7979                   positionID = parent.GetPositionID(this);
7980                   parent.numPositions++;
7981                   if(state == minimized) parent.numIcons--;
7982                }
7983
7984                // *** FONT INHERITANCE ***
7985                if(!setFont && oldParent)
7986                   stopwatching(oldParent, font);
7987
7988                if(systemFont)
7989                {
7990                   RemoveResource(systemFont);
7991                   delete systemFont;
7992                }
7993                // TESTING WITH WATCHERS:
7994                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7995                // usedFont = setFont ? setFont : (systemFont);
7996
7997                if(!usedFont)
7998                {
7999                   if(guiApp.currentSkin)
8000                   {
8001                      systemFont = guiApp.currentSkin.SystemFont();
8002                      incref systemFont;
8003                   }
8004                   usedFont = systemFont;
8005                   AddResource(systemFont);
8006                }
8007
8008                if(!setFont)
8009                   watch(value)
8010                   {
8011                      font
8012                      {
8013                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8014                         firewatchers font;
8015                         Update(null);
8016                      }
8017                   };
8018
8019                firewatchers font;
8020
8021
8022                if(value.rootWindow && value.rootWindow.display && rootWindow)
8023                {
8024                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) ||
8025                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
8026
8027                   if(reloadGraphics)
8028                      UnloadGraphics(false);
8029                   SetupDisplay();
8030                   if(reloadGraphics)
8031                      LoadGraphics(false, false);
8032
8033                   /*
8034                   if(value.rootWindow != rootWindow)
8035                      DisplayModeChanged();
8036                   else
8037                   */
8038                }
8039                scrolledPos.x = MININT; // Prevent parent update
8040                {
8041                   bool anchored = this.anchored;
8042                   property::anchor = anchor;
8043                   this.anchored = anchored;
8044                }
8045                /*
8046                {
8047                   int x, y, w, h;
8048                   if(guiApp.currentSkin)
8049                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
8050
8051                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8052                   Position(x, y, w, h, true, true, true, true, false, true);
8053                }
8054                */
8055
8056             }
8057             // else parent = value;
8058             if(oldParent)
8059                oldParent.OnChildAddedOrRemoved(this, true);
8060          }
8061       }
8062       get { return parent; }
8063    };
8064
8065    property Window master
8066    {
8067       property_category $"Behavior"
8068       set
8069       {
8070          //if(this == value) return;
8071          if(value && value.IsSlaveOf(this)) return;
8072
8073          if(master != value)
8074          {
8075             if(master)
8076             {
8077                OldLink slaveHolder;
8078                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8079                   if(slaveHolder.data == this)
8080                   {
8081                      master.slaves.Delete(slaveHolder);
8082                      break;
8083                   }
8084             }
8085
8086             if(value)
8087             {
8088                value.slaves.Add(OldLink { data = this });
8089
8090                if(hotKey)
8091                {
8092                   if(master)
8093                      master.hotKeys.Remove(hotKey);
8094                   value.hotKeys.Add(hotKey);
8095                   hotKey = null;
8096                }
8097                if(master && master.defaultControl == this)
8098                   master.defaultControl = null;
8099
8100                if(style.isDefault && !value.defaultControl)
8101                   value.defaultControl = this;
8102             }
8103          }
8104          master = value;
8105       }
8106       get { return master ? master : parent; }
8107    };
8108
8109    property char * caption
8110    {
8111       property_category $"Appearance"
8112       watchable
8113       set
8114       {
8115          delete caption;
8116          if(value)
8117          {
8118             caption = new char[strlen(value)+1];
8119             if(caption)
8120                strcpy(caption, value);
8121          }
8122          if(created)
8123             UpdateCaption();
8124       }
8125       get { return caption; }
8126    };
8127
8128    property Key hotKey
8129    {
8130       property_category $"Behavior"
8131       set
8132       {
8133          setHotKey = value;
8134          if(created)
8135          {
8136             if(value)
8137             {
8138                if(!hotKey)
8139                   master.hotKeys.Add(hotKey = HotKeySlot { });
8140                if(hotKey)
8141                {
8142                   hotKey.key = value;
8143                   hotKey.window = this;
8144                }
8145             }
8146             else if(hotKey)
8147             {
8148                master.hotKeys.Delete(hotKey);
8149                hotKey = null;
8150             }
8151          }
8152       }
8153       get { return hotKey ? hotKey.key : 0; }
8154    };
8155
8156    property Color background
8157    {
8158       property_category $"Appearance"
8159       set
8160       {
8161          background.color = value;
8162          firewatchers;
8163          if(created)
8164          {
8165             Update(null);
8166             if(this == rootWindow)
8167                guiApp.interfaceDriver.SetRootWindowColor(this);
8168          }
8169       }
8170       get { return background.color; }
8171    };
8172
8173    property Percentage opacity
8174    {
8175       property_category $"Appearance"
8176       set
8177       {
8178          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8179          drawBehind = (background.a == 255) ? false : true;
8180       }
8181       get { return background.a / 255.0f; }
8182    };
8183
8184    property Color foreground
8185    {
8186       property_category $"Appearance"
8187       set
8188       {
8189          foreground = value;
8190          firewatchers;
8191          if(created)
8192             Update(null);
8193       }
8194       get { return foreground; }
8195    };
8196
8197    property BorderStyle borderStyle
8198    {
8199       property_category $"Appearance"
8200       set
8201       {
8202          if(!((BorderBits)value).fixed)
8203          {
8204             style.hasClose = false;
8205             style.hasMaximize = false;
8206             style.hasMinimize = false;
8207             nativeDecorations = false;
8208          }
8209          style.borderBits = value;
8210          if(created)
8211          {
8212             int x, y, w, h;
8213             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8214
8215             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8216             Position(x, y, w, h, true, true, true, true, false, true);
8217             CreateSystemChildren();
8218          }
8219       }
8220       get { return (BorderStyle)style.borderBits; }
8221    };
8222
8223    property Size minClientSize
8224    {
8225       property_category $"Layout"
8226       set { minSize = value; }
8227       get { value = minSize; }
8228    };
8229
8230    property Size maxClientSize
8231    {
8232       property_category $"Layout"
8233       set { maxSize = value; }
8234       get { value = maxSize; }
8235    };
8236
8237    property bool hasMaximize
8238    {
8239       property_category $"Window Style"
8240       set
8241       {
8242          style.hasMaximize = value;
8243          if(value) { style.fixed = true; style.contour = true; }
8244          if(created)
8245          {
8246             int x, y, w, h;
8247             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8248
8249             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8250             Position(x, y, w, h, true, true, true, true, false, true);
8251
8252             CreateSystemChildren();
8253          }
8254       }
8255       get { return style.hasMaximize; }
8256    };
8257
8258    property bool hasMinimize
8259    {
8260       property_category $"Window Style"
8261       set
8262       {
8263          style.hasMinimize = value;
8264          if(value) { style.fixed = true; style.contour = true; }
8265          if(created)
8266          {
8267             int x, y, w, h;
8268             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8269
8270             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8271             Position(x, y, w, h, true, true, true, true, false, true);
8272
8273             CreateSystemChildren();
8274          }
8275       }
8276       get { return style.hasMinimize;  }
8277    };
8278
8279    property bool hasClose
8280    {
8281       property_category $"Window Style"
8282       set
8283       {
8284          style.hasClose = value;
8285          if(value) { style.fixed = true; style.contour = true; }
8286          if(created)
8287          {
8288             int x, y, w, h;
8289             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8290             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8291             Position(x, y, w, h, true, true, true, true, false, true);
8292             CreateSystemChildren();
8293          }
8294       }
8295       get { return style.hasClose; }
8296    };
8297
8298    property bool nonClient
8299    {
8300       property_category $"Layout"
8301       set
8302       {
8303          style.nonClient = value;
8304          if(value)
8305             style.stayOnTop = true;
8306       }
8307       get { return style.nonClient; }
8308    };
8309
8310    property bool inactive
8311    {
8312       property_category $"Behavior"
8313       set
8314       {
8315          if(value)
8316          {
8317             // *** NEW HERE: ***
8318             if(!style.inactive)
8319             {
8320                if(cycle)
8321                   parent.childrenCycle.Delete(cycle);
8322                if(order)
8323                   parent.childrenOrder.Delete(order);
8324                cycle = null;
8325                order = null;
8326             }
8327
8328             if(created)
8329             {
8330                active = false; // true;
8331                if(parent.activeChild == this)
8332                   parent.activeChild = null;
8333                if(parent.activeClient == this)
8334                   parent.activeClient = null;
8335             }
8336          }
8337          else
8338          {
8339             if(style.inactive)
8340             {
8341                if(!style.noCycle)
8342                {
8343                   parent.childrenCycle.Insert(
8344                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8345                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8346                      null,
8347                      cycle = OldLink { data = this });
8348                }
8349                parent.childrenOrder.Insert(
8350                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8351                   order = OldLink { data = this });
8352             }
8353          }
8354          style.inactive = value;
8355       }
8356       get { return style.inactive; }
8357    };
8358
8359    property bool clickThrough
8360    {
8361       property_category $"Behavior"
8362       set { style.clickThrough = value; }
8363       get { return style.clickThrough; }
8364    };
8365
8366    property bool isRemote
8367    {
8368       property_category $"Behavior"
8369       set { style.isRemote = value; }
8370       get { return style.isRemote; }
8371    };
8372
8373    property bool noCycle
8374    {
8375       property_category $"Behavior"
8376       set { style.noCycle = value; }
8377       get { return style.noCycle; }
8378    };
8379
8380    property bool isModal
8381    {
8382       property_category $"Behavior"
8383       set { style.modal = value; }
8384       get { return style.modal; }
8385    };
8386
8387    property bool interim
8388    {
8389       property_category $"Behavior"
8390       set { style.interim = value; }
8391       get { return style.interim; }
8392    };
8393
8394    property bool tabCycle
8395    {
8396       property_category $"Behavior"
8397       set { style.tabCycle = value; }
8398       get { return style.tabCycle; }
8399    };
8400
8401    property bool isDefault
8402    {
8403       property_category $"Behavior"
8404       set
8405       {
8406          if(master)
8407          {
8408             if(value)
8409             {
8410                Window sibling;
8411                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8412                   if(sibling != this && sibling.style.isDefault)
8413                      sibling.style.isDefault = false;*/
8414                if(master.defaultControl)
8415                   master.defaultControl.style.isDefault = false;
8416                master.defaultControl = this;
8417             }
8418             else if(master.defaultControl == this)
8419                master.defaultControl = null;
8420
8421             // Update(null);
8422          }
8423          style.isDefault = value;
8424          if(created)
8425             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8426       }
8427       get { return style.isDefault; }
8428    };
8429
8430    property bool drawBehind
8431    {
8432       property_category $"Window Style"
8433       set { style.drawBehind = value; }
8434       get { return style.drawBehind; }
8435    };
8436
8437    property bool hasMenuBar
8438    {
8439       property_category $"Window Style"
8440       set
8441       {
8442          if(value)
8443          {
8444             if(!menu)
8445             {
8446                menu = Menu { };
8447                incref menu;
8448             }
8449             if(created && !menuBar)
8450             {
8451                menuBar =
8452                   PopupMenu
8453                   {
8454                      this, menu = menu,
8455                      isMenuBar = true,
8456                      anchor = Anchor { top = 23, left = 1, right = 1 },
8457                      size.h = 24,
8458                      inactive = true, nonClient = true
8459                   };
8460                menuBar.Create();
8461             }
8462          }
8463          else if(created && menuBar)
8464          {
8465             menuBar.Destroy(0);
8466             menuBar = null;
8467          }
8468          style.hasMenuBar = value;
8469       }
8470       get { return style.hasMenuBar; }
8471    };
8472
8473    property bool hasStatusBar
8474    {
8475       property_category $"Window Style"
8476       set
8477       {
8478          if(value)
8479          {
8480             if(!statusBar)
8481             {
8482                statusBar = StatusBar { this };
8483                incref statusBar;
8484                if(created)
8485                   statusBar.Create();
8486             }
8487          }
8488          else if(statusBar)
8489             delete statusBar;
8490          style.hasStatusBar = value;
8491       }
8492       get { return style.hasStatusBar; }
8493    };
8494    property bool stayOnTop
8495    {
8496       property_category $"Window Style"
8497       set
8498       {
8499          if(value)
8500          {
8501             if(created && !style.stayOnTop)
8502             {
8503                if(rootWindow == this)
8504                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8505                else if(parent.children.last != this)
8506                {
8507                   parent.children.Move(this, parent.children.last);
8508                   Update(null);
8509                }
8510             }
8511             style.stayOnTop = true;
8512          }
8513          else
8514          {
8515             if(created && style.stayOnTop)
8516             {
8517                if(rootWindow == this)
8518                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8519                else
8520                {
8521                   Window last;
8522                   if(order)
8523                   {
8524                      OldLink order;
8525                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev;
8526                          order && ((Window)order.data).style.stayOnTop;
8527                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8528                       last = order ? order.data : null;
8529                   }
8530                   else
8531                   {
8532                      for(last = parent.children.last;
8533                          last && last.style.stayOnTop;
8534                          last = last.prev);
8535                   }
8536
8537                   parent.children.Move(this, last);
8538                   Update(null);
8539                }
8540             }
8541             style.stayOnTop = false;
8542          }
8543       }
8544       get { return style.stayOnTop; }
8545    };
8546
8547    property Menu menu
8548    {
8549       property_category $"Window Style"
8550       set
8551       {
8552          delete menu;
8553          if(value)
8554          {
8555             menu = value;
8556             incref menu;
8557          }
8558
8559          if(menuBar && !value)
8560          {
8561             menuBar.Destroy(0);
8562             menuBar = null;
8563          }
8564          if(created)
8565          {
8566             if(!menuBar && style.hasMenuBar && value)
8567             {
8568                menuBar = PopupMenu
8569                          {
8570                             this, menu = value, isMenuBar = true,
8571                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24,
8572                             inactive = true, nonClient = true
8573                          };
8574                 menuBar.Create();
8575             }
8576             UpdateActiveDocument(null);
8577          }
8578       }
8579       get { return menu; }
8580    };
8581
8582    property FontResource font
8583    {
8584       property_category $"Appearance"
8585       watchable
8586       isset { return setFont ? true : false; }
8587       set
8588       {
8589          if(this)
8590          {
8591             if(value && !setFont) { stopwatching(parent, font); }
8592             else if(!value && setFont)
8593             {
8594                watch(parent)
8595                {
8596                   font
8597                   {
8598                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8599                      firewatchers font;
8600                      Update(null);
8601                   }
8602                };
8603             }
8604
8605             if(setFont)
8606             {
8607                RemoveResource(setFont);
8608                delete setFont;
8609             }
8610             if(systemFont)
8611             {
8612                RemoveResource(systemFont);
8613                delete systemFont;
8614             }
8615             setFont = value;
8616             if(setFont)
8617             {
8618                incref setFont;
8619                AddResource(setFont);
8620             }
8621
8622             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8623             if(!usedFont)
8624             {
8625                systemFont = guiApp.currentSkin.SystemFont();
8626                incref systemFont;
8627                usedFont = systemFont;
8628                AddResource(systemFont);
8629             }
8630
8631             firewatchers;
8632
8633             Update(null);
8634          }
8635       }
8636       get { return usedFont; }
8637    };
8638
8639    property SizeAnchor sizeAnchor
8640    {
8641       property_category $"Layout"
8642       isset
8643       {
8644          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8645                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8646             sizeAnchor.isClientW != sizeAnchor.isClientH;
8647       }
8648       set
8649       {
8650          int x, y, w, h;
8651          sizeAnchor = value;
8652
8653          normalSizeAnchor = sizeAnchor;
8654
8655          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8656          {
8657             stateAnchor = normalAnchor;
8658             stateSizeAnchor = normalSizeAnchor;
8659
8660             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8661             Position(x,y, w, h, true, true, true, true, false, true);
8662          }
8663       }
8664       get
8665       {
8666          value =
8667          {
8668             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8669             sizeAnchor.isClientW,
8670             sizeAnchor.isClientH
8671          };
8672       }
8673    };
8674
8675    property Size size
8676    {
8677       property_category $"Layout"
8678       isset
8679       {
8680          Anchor thisAnchor = anchor;
8681          SizeAnchor thisSizeAnchor = sizeAnchor;
8682          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8683          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8684          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8685          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8686                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8687             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8688       }
8689       set
8690       {
8691          int x, y, w, h;
8692
8693          sizeAnchor.isClientW = false;
8694          sizeAnchor.isClientH = false;
8695          sizeAnchor.size = value;
8696
8697          normalSizeAnchor = sizeAnchor;
8698
8699          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8700          {
8701             stateAnchor = normalAnchor;
8702             stateSizeAnchor = normalSizeAnchor;
8703
8704             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8705             Position(x, y, w, h, true, true, true, true, false, true);
8706             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8707          }
8708       }
8709       get { value = size; }
8710    };
8711
8712    property Size clientSize
8713    {
8714       property_category $"Layout"
8715       isset
8716       {
8717          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8718                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8719             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8720       }
8721       set
8722       {
8723          int x, y, w, h;
8724          sizeAnchor.isClientW = true;
8725          sizeAnchor.isClientH = true;
8726          sizeAnchor.size = value;
8727
8728          normalSizeAnchor = sizeAnchor;
8729
8730          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8731          {
8732             stateAnchor = normalAnchor;
8733             stateSizeAnchor = normalSizeAnchor;
8734
8735             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8736             Position(x,y, w, h, true, true, true, true, false, true);
8737             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8738          }
8739       }
8740       get { value = this ? clientSize : { 0, 0 }; }
8741    };
8742
8743    property Size initSize { get { value = sizeAnchor.size; } };
8744
8745    property Anchor anchor
8746    {
8747       property_category $"Layout"
8748       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8749
8750       set
8751       {
8752          if(value != null)
8753          {
8754             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8755             {
8756                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8757                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8758             }
8759             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8760             {
8761                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8762                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8763             }
8764             anchor = value;
8765
8766             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type))
8767             {
8768                anchor.left.distance = 0;
8769                anchor.horz.type = 0;
8770             }
8771             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8772             {
8773                anchor.top.distance = 0;
8774                anchor.vert.type = 0;
8775             }
8776
8777             anchored = true;
8778
8779             //if(created)
8780             {
8781                int x, y, w, h;
8782
8783                normalAnchor = anchor;
8784
8785                // Break the anchors for moveable/resizable windows
8786                /*if(style.fixed ) //&& value.left.type == cascade)
8787                {
8788                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8789
8790                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8791                   normalSizeAnchor = SizeAnchor { { w, h } };
8792                   anchored = false;
8793                }*/
8794                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8795                {
8796                   stateAnchor = normalAnchor;
8797                   stateSizeAnchor = normalSizeAnchor;
8798
8799                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8800                   Position(x, y, w, h, true, true, true, true, false, true);
8801                }
8802             }
8803          }
8804          else
8805          {
8806             anchored = false;
8807          }
8808       }
8809       get { value = this ? anchor : Anchor { }; }
8810    };
8811
8812    property Point position
8813    {
8814       property_category $"Layout"
8815       set
8816       {
8817          if(value == null) return;
8818
8819          anchor.left = value.x;
8820          anchor.top  = value.y;
8821          anchor.right.type = none;
8822          anchor.bottom.type = none;
8823          //if(created)
8824          {
8825             int x, y, w, h;
8826
8827             normalAnchor = anchor;
8828
8829             // Break the anchors for moveable/resizable windows
8830             /*
8831             if(style.fixed)
8832             {
8833                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8834
8835                normalAnchor.left = x;
8836                normalAnchor.top = y;
8837                normalAnchor.right.type = none;
8838                normalAnchor.bottom.type = none;
8839                normalSizeAnchor.size.width = w;
8840                normalSizeAnchor.size.height = h;
8841                anchored = false;
8842             }
8843             */
8844             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8845             {
8846                stateAnchor = normalAnchor;
8847                stateSizeAnchor = normalSizeAnchor;
8848
8849                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8850                Position(x,y, w, h, true, true, true, true, false, true);
8851             }
8852          }
8853       }
8854       get { value = position; }
8855    };
8856
8857    property bool disabled
8858    {
8859       property_category $"Behavior"
8860       set
8861       {
8862          if(this && disabled != value)
8863          {
8864             disabled = value;
8865             if(created)
8866                Update(null);
8867          }
8868       }
8869       get { return (bool)disabled; }
8870    };
8871
8872    property bool isEnabled
8873    {
8874       get
8875       {
8876          Window parent;
8877          for(parent = this; parent; parent = parent.parent)
8878             if(parent.disabled)
8879                return false;
8880          return true;
8881       }
8882    };
8883
8884    property WindowState state
8885    {
8886       property_category $"Behavior"
8887       set { SetState(value, false, 0); }
8888       get { return this ? state : 0; }
8889    };
8890
8891    property bool visible
8892    {
8893       property_category $"Behavior"
8894       set
8895       {
8896          if(this && !value && !style.hidden && parent)
8897          {
8898             bool wasActiveChild = parent.activeChild == this;
8899             Window client = null;
8900
8901             style.hidden = true;
8902             if(style.isActiveClient)
8903             {
8904                parent.numPositions--;
8905                if(state == minimized) parent.numIcons--;
8906             }
8907
8908             if(created)
8909             {
8910                OldLink prevOrder = null;
8911
8912                if(rootWindow == this)
8913                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8914                else
8915                {
8916                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8917                   if(style.nonClient)
8918                   {
8919                      box.left   -= parent.clientStart.x;
8920                      box.top    -= parent.clientStart.y;
8921                      box.right  -= parent.clientStart.x;
8922                      box.bottom -= parent.clientStart.y;
8923                   }
8924                   parent.Update(box);
8925                }
8926                if(_isModal && master && master.modalSlave == this)
8927                   master.modalSlave = null;
8928
8929                if(order)
8930                {
8931                   OldLink tmpPrev = order.prev;
8932                   client = tmpPrev ? tmpPrev.data : null;
8933                   if(client && !client.style.hidden && !client.destroyed && client.created)
8934                      prevOrder = tmpPrev;
8935                   for(;;)
8936                   {
8937                      client = tmpPrev ? tmpPrev.data : null;
8938                      if(client == this) { client = null; break; }
8939                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8940                      {
8941                         tmpPrev = client.order.prev;
8942                      }
8943                      else
8944                      {
8945                         if(client)
8946                            prevOrder = tmpPrev;
8947                         break;
8948                      }
8949                   }
8950
8951                   // If this window can be an active client, make sure the next window we activate can also be one
8952                   if(!style.nonClient && style.isActiveClient)
8953                   {
8954                      tmpPrev = prevOrder;
8955                      for(;;)
8956                      {
8957                         client = tmpPrev ? tmpPrev.data : null;
8958                         if(client == this) { client = null; break; }
8959                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8960                         {
8961                            tmpPrev = client.order.prev;
8962                         }
8963                         else
8964                         {
8965                            if(client)
8966                               prevOrder = tmpPrev;
8967                            break;
8968                         }
8969                      }
8970                      if(client && client.style.hidden) client = null;
8971                   }
8972                }
8973
8974                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
8975                {
8976                   if(order && prevOrder && prevOrder.data != this)
8977                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8978                   else
8979                      ActivateEx(false, false, false, true, null, null);
8980
8981                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8982                   if(parent.activeClient == this)
8983                   {
8984                      parent.activeClient = null;
8985                      parent.UpdateActiveDocument(null);
8986                   }
8987                }
8988                else if(parent.activeClient == this)
8989                {
8990                   parent.activeClient = client;
8991                   parent.UpdateActiveDocument(this);
8992                }
8993
8994                // *** Not doing this anymore ***
8995               /*
8996                if(cycle)
8997                   parent.childrenCycle.Delete(cycle);
8998                if(order)
8999                   parent.childrenOrder.Delete(order);
9000                cycle = null;
9001                order = null;
9002                */
9003
9004                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9005             }
9006
9007             firewatchers;
9008          }
9009          else if(this && value && style.hidden)
9010          {
9011             style.hidden = false;
9012             if(created)
9013             {
9014                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9015                if(rootWindow == this)
9016                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
9017
9018                if(_isModal && master)
9019                   master.modalSlave = this;
9020
9021                if(style.isActiveClient)
9022                {
9023                   positionID = parent.GetPositionID(this);
9024                   parent.numPositions++;
9025                   if(state == minimized) parent.numIcons++;
9026                }
9027
9028                // *** NOT DOING THIS ANYMORE ***
9029                /*
9030                if(!(style.inactive))
9031                {
9032                   if(!(style.noCycle))
9033                   {
9034                      cycle = parent.childrenCycle.AddAfter(
9035                         (parent.activeChild && parent.activeChild.cycle) ?
9036                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
9037                      cycle.data = this;
9038                   }
9039                   order = parent.childrenOrder.AddAfter(
9040                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
9041                      sizeof(OldLink));
9042                   order.data = this;
9043                }
9044                */
9045
9046                /*
9047                if(true || !parent.activeChild)
9048                   ActivateEx(true, false, true, true, null, null);
9049                */
9050                if(creationActivation == activate)
9051                   ActivateEx(true, false, true, true, null, null);
9052                else if(creationActivation == flash && !object)
9053                   Flash();
9054
9055                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9056                Update(null);
9057
9058                // rootWindow.
9059                ConsequentialMouseMove(false);
9060             }
9061
9062             firewatchers;
9063          }
9064          else if(this)
9065             style.hidden = !value;
9066       }
9067
9068       get { return (style.hidden || !setVisible) ? false : true; }
9069    };
9070
9071    property bool isDocument
9072    {
9073       property_category $"Document"
9074       set { style.isDocument = value; }
9075       get { return style.isDocument; }
9076    };
9077
9078    property bool mergeMenus
9079    {
9080       property_category $"Window Style"
9081       set { mergeMenus = value; }
9082       get { return (bool)mergeMenus; }
9083    };
9084
9085    property bool hasHorzScroll
9086    {
9087       property_category $"Window Style"
9088       set
9089       {
9090          if(value)
9091          {
9092             if(!style.hasHorzScroll && created)
9093             {
9094                CreateSystemChildren();
9095                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9096             }
9097          }
9098          else if(style.hasHorzScroll)
9099          {
9100             sbh.Destroy(0);
9101             sbh = null;
9102             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9103          }
9104          style.hasHorzScroll = value;
9105       }
9106
9107       get { return style.hasHorzScroll; }
9108    };
9109
9110    property bool hasVertScroll
9111    {
9112       property_category $"Window Style"
9113       set
9114       {
9115          if(value)
9116          {
9117             if(!style.hasVertScroll && created)
9118             {
9119                style.hasVertScroll = true;
9120                CreateSystemChildren();
9121                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9122             }
9123          }
9124          else if(style.hasVertScroll)
9125          {
9126             sbv.Destroy(0);
9127             sbv = null;
9128             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9129          }
9130          style.hasVertScroll = value;
9131       }
9132       get { return style.hasVertScroll; }
9133    };
9134
9135    property bool dontHideScroll
9136    {
9137       property_category $"Behavior"
9138       set
9139       {
9140          scrollFlags.dontHide = value;
9141          if(value)
9142          {
9143             //UpdateScrollBars(true, true);
9144             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9145          }
9146          else
9147          {
9148             // UpdateScrollBars(true, true);
9149             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9150          }
9151       }
9152       get { return scrollFlags.dontHide; }
9153    };
9154
9155    property bool dontScrollVert
9156    {
9157       property_category $"Behavior"
9158       set { style.dontScrollVert = value; }
9159       get { return style.dontScrollVert; }
9160    };
9161    property bool dontScrollHorz
9162    {
9163       property_category $"Behavior"
9164       set { style.dontScrollHorz = value; }
9165       get { return style.dontScrollHorz; }
9166    };
9167
9168    property bool snapVertScroll
9169    {
9170       property_category $"Behavior"
9171       set
9172       {
9173          scrollFlags.snapY = value;
9174          if(sbv) sbv.snap = value;
9175       }
9176       get { return scrollFlags.snapY; }
9177    };
9178    property bool snapHorzScroll
9179    {
9180        property_category $"Behavior"
9181       set
9182       {
9183          scrollFlags.snapX = value;
9184          if(sbh) sbh.snap = value;
9185       }
9186       get { return scrollFlags.snapX; }
9187    };
9188
9189    property Point scroll
9190    {
9191       property_category $"Behavior"
9192       set { if(this) SetScrollPosition(value.x, value.y); }
9193       get { value = scroll; }
9194    };
9195
9196    property bool modifyVirtualArea
9197    {
9198       property_category $"Behavior"
9199       set { modifyVirtArea = value; }
9200       get { return (bool)modifyVirtArea; }
9201    };
9202
9203    property bool dontAutoScrollArea
9204    {
9205       property_category $"Behavior"
9206       // Activating a child control out of view will automatically scroll to make it in view
9207       set { noAutoScrollArea = value; }
9208       get { return (bool)noAutoScrollArea; }
9209    };
9210
9211    property char * fileName
9212    {
9213       property_category $"Document"
9214       set
9215       {
9216          if(menu && ((!fileName && value) || (fileName && !value)))
9217          {
9218             MenuItem item = menu.FindItem(MenuFileSave, 0);
9219             if(item) item.disabled = !modifiedDocument && value;
9220          }
9221
9222          delete fileName;
9223
9224          if(value && value[0])
9225             fileName = CopyString(value);
9226
9227          if(parent && this == parent.activeClient)
9228             parent.UpdateActiveDocument(null);
9229          else
9230             UpdateCaption();
9231
9232          // if(style.isDocument)
9233          if(!saving)
9234             fileMonitor.fileName = value;
9235       }
9236       get { return fileName; }
9237    };
9238
9239    property int64 id
9240    {
9241       property_category $"Data"
9242       set { id = value; }
9243       get { return id; }
9244    };
9245
9246    property bool modifiedDocument
9247    {
9248       property_category $"Document"
9249       set
9250       {
9251          if(style.isDocument || fileName)
9252          {
9253             if(menu)
9254             {
9255                MenuItem item = menu.FindItem(MenuFileSave, 0);
9256                if(item) item.disabled = !value && fileName;
9257             }
9258          }
9259
9260          if(modifiedDocument != value)
9261          {
9262             modifiedDocument = value;
9263             if(style.isDocument || fileName)
9264                UpdateCaption();
9265          }
9266       }
9267       get { return (bool)modifiedDocument; }
9268    };
9269
9270    property bool showInTaskBar
9271    {
9272       property_category $"Window Style"
9273       set { style.showInTaskBar = value; }
9274       get { return (style.showInTaskBar; }
9275    };
9276    property FileDialog saveDialog { set { saveDialog = value; } };
9277    property bool isActiveClient
9278    {
9279       property_category $"Behavior"
9280       set { style.isActiveClient = value; }
9281       get { return style.isActiveClient; }
9282    };
9283
9284    property Cursor cursor
9285    {
9286       property_category $"Appearance"
9287       set
9288       {
9289          cursor = value;
9290          SelectMouseCursor();
9291       }
9292       get { return cursor; }
9293    };
9294
9295 //#if !defined(ECERE_VANILLA)
9296    property char * name
9297    {
9298       property_category $"Design"
9299       get
9300       {
9301          return (this && object) ? object.name : null;
9302       }
9303       set
9304       {
9305          if(activeDesigner)
9306             activeDesigner.RenameObject(object, value);
9307       }
9308    };
9309 //#endif
9310    property char * displayDriver
9311    {
9312       property_category $"Behavior"
9313       set
9314       {
9315          dispDriver = GetDisplayDriver(value);
9316          //DisplayModeChanged();
9317       }
9318       get
9319       {
9320          return dispDriver ? dispDriver.name : null;
9321       }
9322    }
9323
9324    // RUNTIME PROPERTIES
9325    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9326    property Size scrollArea
9327    {
9328       property_category $"Behavior"
9329       set
9330       {
9331          if(value != null)
9332             SetScrollArea(value.w, value.h, false);
9333          else
9334             SetScrollArea(0,0, true);
9335       }
9336       get { value = scrollArea; }
9337       isset
9338       {
9339          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9340       }
9341    };
9342    property bool is3D
9343    {
9344       property_category $"Layout"
9345       set { if(this) is3D = value; }
9346       get { return (bool)is3D; }
9347    };
9348
9349    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9350
9351    // Will be merged with font later
9352    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9353    property Point clientStart { get { value = clientStart; } };
9354    property Point absPosition { get { value = absPosition; } };
9355    property Anchor normalAnchor { get { value = normalAnchor; } };
9356    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9357    property bool active { get { return (bool)active; } };
9358    property bool created { get { return (bool)created; } };
9359    property bool destroyed { get { return (bool)destroyed; } };
9360    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9361    property Window firstChild { get { return children.first; } };
9362    property Window lastChild { get { return children.last; } };
9363    property Window activeClient { get { return activeClient; } };
9364    property Window activeChild { get { return activeChild; } };
9365    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9366    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9367    property ScrollBar horzScroll { get { return sbh; } };
9368    property ScrollBar vertScroll { get { return sbv; } };
9369    property StatusBar statusBar { get { return statusBar; } };
9370    property Window rootWindow { get { return rootWindow; } };
9371    property bool closing { get { return (bool)closing; } set { closing = value; } };
9372    property int documentID { get { return documentID; } };
9373    property Window previous { get { return prev; } }
9374    property Window next { get { return next; } }
9375    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9376    property PopupMenu menuBar { get { return menuBar; } }
9377    property ScrollBar sbv { get { return sbv; } }
9378    property ScrollBar sbh { get { return sbh; } }
9379    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9380    property void * systemHandle { get { return windowHandle; } }
9381    property Button minimizeButton { get { return sysButtons[0]; } };
9382    property Button maximizeButton { get { return sysButtons[1]; } };
9383    property Button closeButton { get { return sysButtons[2]; } };
9384    property BitmapResource icon
9385    {
9386       get { return icon; }
9387       set
9388       {
9389          icon = value;
9390          if(icon) incref icon;
9391          if(created)
9392             guiApp.interfaceDriver.SetIcon(this, value);
9393       }
9394    };
9395    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9396    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9397    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9398    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9399    property bool nativeDecorations
9400    {
9401       get { return (bool)nativeDecorations; }
9402       set { nativeDecorations = value; }
9403 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9404       isset
9405       {
9406          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9407          bool result = false;
9408          if(nativeDecorations)
9409          {
9410             if(rootWindow == this)
9411                result = true;
9412             else
9413             {
9414                if(formDesigner && activeDesigner)
9415                {
9416                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9417                   Window form = cd ? cd.form : null;
9418                   if(form && parent == form.parent)
9419                      result = true;
9420                }
9421             }
9422          }
9423          return result != style.fixed;
9424       }
9425 #endif
9426    };
9427    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9428
9429    property char * text
9430    {
9431       property_category $"Deprecated"
9432       watchable
9433       set { property::caption = value; }
9434       get { return property::caption; }
9435    }
9436 private:
9437    // Data
9438    //char * yo;
9439    Window prev, next;
9440    WindowBits style;       // Window Style
9441    char * caption;            // Name / Caption
9442    Window parent;    // Parent window
9443    OldList children;          // List of children in Z order
9444    Window activeChild;     // Child window having focus
9445    Window activeClient;
9446    Window previousActive;  // Child active prior to activating the default child
9447    Window master;          // Window owning and receiving notifications concerning this window
9448    OldList slaves;            // List of windows belonging to this window
9449    Display display;        // Display this window is drawn into
9450
9451    Point position;         // Position in parent window client area
9452    Point absPosition;      // Absolute position
9453    Point clientStart;      // Client area position from (0,0) in this window
9454    Size size;              // Size
9455    Size clientSize;        // Client area size
9456    Size scrollArea;        // Virtual Scroll area size
9457    Size reqScrollArea;     // Requested virtual area size
9458    Point scroll;           // Virtual area scrolling position
9459    ScrollBar sbh, sbv;        // Scrollbar window handles
9460    Cursor cursor;        // Mouse cursor used for this window
9461    WindowState state;
9462    PopupMenu menuBar;
9463    StatusBar statusBar;
9464    Button sysButtons[3];
9465    char * fileName;
9466    Box clientArea;         // Client Area box clipped to parent
9467    Key setHotKey;
9468    HotKeySlot hotKey;        // HotKey for this window
9469    int numDocuments;
9470    int numPositions;
9471    Menu menu;
9472    ScrollFlags scrollFlags;// Window Scrollbar Flags
9473    int64 id;                 // Control ID
9474    int documentID;
9475    ColorAlpha background;  // Background color used to draw the window area
9476    Color foreground;
9477    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9478    OldList childrenCycle;     // Cycling order
9479    OldLink cycle;             // Element of parent's cycling order
9480    OldList childrenOrder;     // Circular Z-Order
9481    OldLink order;             // Element of parent's circular Z-Order
9482    Window modalSlave;      // Slave window blocking this window's interaction
9483
9484    Window rootWindow;      // Topmost system managed window
9485    void * windowHandle;    // System window handle
9486
9487    DialogResult returnCode;// Return code for modal windows
9488
9489    Point sbStep;           // Scrollbar line scrolling steps
9490
9491    Anchor stateAnchor;
9492    SizeAnchor stateSizeAnchor;
9493
9494    Anchor normalAnchor;
9495    SizeAnchor normalSizeAnchor;
9496
9497    Size skinMinSize;       // Minimal window size based on style
9498    Point scrolledPos;      // Scrolled position
9499    Box box;                // Window box clipped to parent
9500    Box * against;          // What to clip the box to
9501
9502    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9503    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9504    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9505    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9506    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9507    Point scrolledArea;     // Distance to scroll area by
9508    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9509
9510    OldList hotKeys;           // List of the hotkeys of all children
9511    Window defaultControl;  // Default child control
9512    Size minSize;
9513    Size maxSize;
9514
9515    ColorAlpha * palette;   // Color palette used for this window
9516
9517    int caretSize;          // Size of caret, non zero if a caret is present
9518    Point caretPos;         // Caret position
9519
9520    void * systemParent;    // Parent System Window for embedded windows
9521
9522    int iconID;
9523    int numIcons;
9524    int positionID;
9525
9526    Mutex mutex;
9527    WindowState lastState;
9528
9529    FileMonitor fileMonitor
9530    {
9531       this, FileChange { modified = true };
9532
9533       bool OnFileNotify(FileChange action, char * param)
9534       {
9535          incref this;
9536          fileMonitor.StopMonitoring();
9537          if(OnFileModified(action, param))
9538             fileMonitor.StartMonitoring();
9539          delete this;
9540          return true;
9541       }
9542    };
9543    FontResource setFont, systemFont;
9544    FontResource usedFont;
9545    FontResource captionFont;
9546    OldList resources;
9547    FileDialog saveDialog;
9548    Anchor anchor;
9549    SizeAnchor sizeAnchor;
9550
9551    // FormDesigner data
9552    ObjectInfo object;
9553    Window control;
9554    Extent * tempExtents; //[4];
9555    BitmapResource icon;
9556    void * windowData;
9557    CreationActivationOption creationActivation;
9558    struct
9559    {
9560       bool active:1;            // true if window and ancestors are active
9561       bool acquiredInput:1;     // true if the window is processing state based input
9562       bool modifiedDocument:1;
9563       bool disabled:1;          // true if window cannot interact
9564       bool isForegroundWindow:1;// true while a root window is being activated
9565       bool visible:1;           // Visibility flag
9566       bool destroyed:1;         // true if window is being destroyed
9567       bool anchored:1;          // true if this window is repositioned when the parent resizes
9568       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9569       bool mouseInside:1;
9570       bool positioned:1;
9571       bool created:1;
9572       bool is3D:1;
9573       bool mergeMenus:1;
9574       bool modifyVirtArea:1;
9575       bool noAutoScrollArea:1;
9576       bool closing:1;
9577       bool autoCreate:1;
9578       bool setVisible:1;      // FOR FORM DESIGNER
9579       bool wasCreated:1;
9580       bool fullRender:1;
9581       bool moveable:1;
9582       bool alphaBlend:1;
9583       bool composing:1;
9584       bool useSharedMemory:1;
9585       bool resized:1;
9586       bool saving:1;
9587       bool nativeDecorations:1;
9588       bool manageDisplay:1;
9589       bool formDesigner:1; // True if we this is running in the form editor
9590       bool requireRemaximize:1;
9591    };
9592
9593    // Checks used internally for them not to take effect in FormDesigner
9594    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9595    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9596
9597    WindowController controller;
9598    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9599 };
9600
9601 public class CommonControl : Window
9602 {
9603    // creationActivation = doNothing;
9604
9605    ToolTip toolTip;
9606    public property String toolTip
9607    {
9608       property_category $"Appearance"
9609       set
9610       {
9611          if(created) CommonControl::OnDestroy();
9612          delete toolTip;
9613          toolTip = value ? ToolTip { tip = value; } : null;
9614          incref toolTip;
9615          if(created) CommonControl::OnCreate();
9616       }
9617       get { return toolTip ? toolTip.tip : null; }
9618    }
9619
9620    void OnDestroy()
9621    {
9622       if(toolTip)
9623          // (Very) Ugly work around for the fact that the parent watcher
9624          // won't fire when it's already been disconnected...
9625          eInstance_FireSelfWatchers(toolTip,
9626             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9627    }
9628
9629    bool OnCreate()
9630    {
9631       if(toolTip)
9632          toolTip.parent = this;
9633       return true;
9634    }
9635    ~CommonControl()
9636    {
9637       delete toolTip;
9638    }
9639 };
9640
9641 public class Percentage : float
9642 {
9643    char * OnGetString(char * string, float * fieldData, bool * needClass)
9644    {
9645       int c;
9646       int last = 0;
9647       sprintf(string, "%.2f", this);
9648       c = strlen(string)-1;
9649       for( ; c >= 0; c--)
9650       {
9651          if(string[c] != '0')
9652             last = Max(last, c);
9653          if(string[c] == '.')
9654          {
9655             if(last == c)
9656                string[c] = 0;
9657             else
9658                string[last+1] = 0;
9659             break;
9660          }
9661       }
9662       return string;
9663    }
9664 };
9665
9666 public void ApplySkin(Class c, char * name, void ** vTbl)
9667 {
9668    char className[1024];
9669    Class sc;
9670    OldLink d;
9671    int m;
9672
9673    subclass(Window) wc = (subclass(Window))c;
9674    subclass(Window) base = (subclass(Window))c.base;
9675
9676    sprintf(className, "%sSkin_%s", name, c.name);
9677    wc.pureVTbl = c._vTbl;
9678    c._vTbl = new void *[c.vTblSize];
9679    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9680    sc = eSystem_FindClass(c.module.application, className);
9681
9682    if(vTbl)
9683    {
9684       for(m = 0; m < c.base.vTblSize; m++)
9685       {
9686          if(c._vTbl[m] == base.pureVTbl[m])
9687             c._vTbl[m] = vTbl[m];
9688       }
9689    }
9690    if(sc)
9691    {
9692       for(m = 0; m < c.vTblSize; m++)
9693       {
9694          if(sc._vTbl[m] != wc.pureVTbl[m])
9695             c._vTbl[m] = sc._vTbl[m];
9696       }
9697    }
9698
9699    for(d = c.derivatives.first; d; d = d.next)
9700    {
9701       ApplySkin(d.data, name, c._vTbl);
9702    }
9703 }
9704
9705 public void UnapplySkin(Class c)
9706 {
9707    char className[1024];
9708    Class sc;
9709    subclass(Window) wc = (subclass(Window))c;
9710    subclass(Window) base = (subclass(Window))c.base;
9711    OldLink d;
9712
9713    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9714    {
9715       delete c._vTbl;
9716       c._vTbl = wc.pureVTbl;
9717       wc.pureVTbl = null;
9718    }
9719
9720    for(d = c.derivatives.first; d; d = d.next)
9721    {
9722       UnapplySkin(d.data);
9723    }
9724 }
9725 /*
9726 void CheckFontIntegrity(Window window)
9727 {
9728    Window c;
9729    if(window)
9730    {
9731       if(window.usedFont && window.usedFont.font == 0xecececec)
9732       {
9733          FontResource uf = window.usedFont;
9734          char * className = window._class.name;
9735          char * text = window.text;
9736          Print("");
9737       }
9738       for(c = window.firstChild; c; c = c.next)
9739          CheckFontIntegrity(c);
9740    }
9741 }*/
9742
9743 public class ControllableWindow : Window
9744 {
9745    /*WindowController controller;
9746    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9747    ~ControllableWindow() { delete controller; }*/
9748 }
9749
9750 class WindowControllerInterface : ControllableWindow
9751 {
9752    bool OnKeyDown(Key key, unichar ch)
9753    {
9754       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch);
9755       if(result)
9756          result = ((bool (*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown])(controller.window, key, ch);
9757       return result;
9758    }
9759
9760    bool OnKeyUp(Key key, unichar ch)
9761    {
9762       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch);
9763       if(result)
9764          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp])(controller.window, key, ch);
9765       return result;
9766    }
9767
9768    bool OnKeyHit(Key key, unichar ch)
9769    {
9770       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch);
9771       if(result)
9772          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit])(controller.window, key, ch);
9773       return result;
9774    }
9775
9776    bool OnMouseMove(int x, int y, Modifiers mods)
9777    {
9778       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods);
9779       if(result)
9780          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove])(controller.window, x, y, mods);
9781       return result;
9782    }
9783
9784    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9785    {
9786       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods);
9787       if(result)
9788          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown])(controller.window, x, y, mods);
9789       return result;
9790    }
9791
9792    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9793    {
9794       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods);
9795       if(result)
9796          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp])(controller.window, x, y, mods);
9797       return result;
9798    }
9799
9800    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9801    {
9802       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9803       if(result)
9804          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick])(controller.window, x, y, mods);
9805       return result;
9806    }
9807
9808    bool OnRightButtonDown(int x, int y, Modifiers mods)
9809    {
9810       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods);
9811       if(result)
9812          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown])(controller.window, x, y, mods);
9813       return result;
9814    }
9815
9816    bool OnRightButtonUp(int x, int y, Modifiers mods)
9817    {
9818       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods);
9819       if(result)
9820          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp])(controller.window, x, y, mods);
9821       return result;
9822    }
9823
9824    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9825    {
9826       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9827       if(result)
9828          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick])(controller.window, x, y, mods);
9829       return result;
9830    }
9831
9832    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9833    {
9834       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods);
9835       if(result)
9836          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown])(controller.window, x, y, mods);
9837       return result;
9838    }
9839
9840    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9841    {
9842       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods);
9843       if(result)
9844          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp])(controller.window, x, y, mods);
9845       return result;
9846    }
9847
9848    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9849    {
9850       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9851       if(result)
9852          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick])(controller.window, x, y, mods);
9853       return result;
9854    }
9855
9856    void OnResize(int width, int height)
9857    {
9858       ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
9859       ((void(*)(Window, int, int))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize])(controller.window, width, height);
9860    }
9861
9862    void OnRedraw(Surface surface)
9863    {
9864       ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
9865       ((void(*)(Window, Surface))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(controller.window, surface);
9866    }
9867
9868    bool OnCreate()
9869    {
9870       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller);
9871       if(result)
9872          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate])(controller.window);
9873       return result;
9874    }
9875
9876    bool OnLoadGraphics()
9877    {
9878       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller);
9879       if(result)
9880          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics])(controller.window);
9881       return result;
9882    }
9883
9884    void OnUnloadGraphics()
9885    {
9886       ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
9887       ((void(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics])(controller.window);
9888    }
9889 }
9890
9891 public class WindowController<class V>
9892 {
9893 public:
9894    property Window window
9895    {
9896       set
9897       {
9898          uint size = class(Window).vTblSize;
9899          if(value)
9900          {
9901             windowVTbl = new void *[size];
9902             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9903             if(value._vTbl == value._class._vTbl)
9904             {
9905                value._vTbl = new void *[value._class.vTblSize];
9906                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9907             }
9908             {
9909                int c;
9910                for(c = 0; c < size; c++)
9911                {
9912                   void * function = class(WindowControllerInterface)._vTbl[c];
9913                   if(function != DefaultFunction)
9914                      value._vTbl[c] = function;
9915                   else
9916                      value._vTbl[c] = windowVTbl[c];
9917                }
9918             }
9919          }
9920          else
9921             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9922          window = value;
9923       }
9924       get { return window; }
9925    }
9926    property V controlled
9927    {
9928       set { controlled = value; }
9929       get { return controlled; }
9930    }
9931    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9932    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9933    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9934    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9935    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9936    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9937    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9938    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9939    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9940    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9941    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9942    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9943    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9944    virtual void V::OnResize(WindowController controller, int width, int height);
9945    virtual void V::OnRedraw(WindowController controller, Surface surface);
9946    virtual bool V::OnCreate(WindowController controller);
9947    virtual bool V::OnLoadGraphics(WindowController controller);
9948    virtual void V::OnUnloadGraphics(WindowController controller);
9949
9950 private:
9951    int (** windowVTbl)();
9952    V controlled;
9953    Window window;
9954
9955    ~WindowController()
9956    {
9957       delete windowVTbl;
9958    }
9959 }