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