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