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