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