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