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