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