ecere/gui/drivers/X11: (#850,#700,#795) Improved X11/Unity fixes
[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)
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)
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       for(menuBarParent = this; menuBarParent; menuBarParent = menuBarParent.parent)
2237       {
2238          if(menuBarParent.menuBar) return menuBarParent.menuBar;
2239          if(menuBarParent && !menuBarParent.isActiveClient)
2240             return null;
2241       }
2242       return null;
2243    }
2244
2245    void CreateSystemChildren(void)
2246    {
2247       Window parent = this;
2248       bool scrollBarChanged = false;
2249       bool hasClose = false, hasMaxMin = false;
2250       Point scroll = this.scroll;
2251
2252       if(state == maximized)
2253       {
2254          parent = GetParentMenuBar();
2255          if(!parent && nativeDecorations)
2256             parent = rootWindow;
2257       }
2258
2259       if(parent)
2260       {
2261          if(style.hasClose) hasClose = true;
2262          if(style.hasMaximize || style.hasMinimize)
2263          {
2264             hasClose = true;
2265             hasMaxMin = true;
2266          }
2267       }
2268
2269       if(sysButtons[2] && (!hasClose || sysButtons[2].parent != parent))
2270       {
2271          sysButtons[2].Destroy(0);
2272          sysButtons[2] = null;
2273       }
2274       if(sysButtons[1] && (!hasMaxMin || sysButtons[1].parent != parent))
2275       {
2276          sysButtons[1].Destroy(0);
2277          sysButtons[1] = null;
2278       }
2279       if(sysButtons[0] && (!hasMaxMin || sysButtons[0].parent != parent))
2280       {
2281          sysButtons[0].Destroy(0);
2282          sysButtons[0] = null;
2283       }
2284       //return;
2285       if(hasClose && parent)
2286       {
2287          if(!sysButtons[2])
2288          {
2289             sysButtons[2] = 
2290                Button
2291                {
2292                   parent, master = this,
2293                   inactive = true, nonClient = true, visible = false;
2294
2295                   bool NotifyClicked(Button button, int x, int y, Modifiers mods)
2296                   {
2297                      Destroy(0);
2298                      return true;
2299                   }
2300                };
2301             if(this.parent == guiApp.desktop)
2302                sysButtons[2].hotKey = altF4;
2303             else if(style.isActiveClient)
2304                sysButtons[2].hotKey = ctrlF4;
2305             sysButtons[2].Create();
2306          }
2307          
2308          sysButtons[2].symbol = 'X';
2309          sysButtons[2].disabled = !style.hasClose;
2310       }
2311
2312       if(hasMaxMin && parent)
2313       {
2314          SkinBitmap skin;
2315          unichar symbol;
2316          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2317          if(state == maximized) 
2318          {
2319             skin = restore;
2320             method = RestoreButtonClicked;
2321             symbol = '\x12';
2322          }
2323          else
2324          {
2325             skin = maximize;
2326             method = MaximizeButtonClicked;
2327             symbol = '\x18';
2328          }
2329          if(!sysButtons[1])
2330          {
2331             sysButtons[1] =
2332                Button
2333                {
2334                   parent, master = this,
2335                   hotKey = altEnter, inactive = true, nonClient = true, visible = false
2336                };
2337             sysButtons[1].Create();
2338          }
2339          sysButtons[1].NotifyClicked = method;
2340
2341          sysButtons[1].symbol = symbol;
2342          sysButtons[1].disabled = !style.hasMaximize;
2343       }
2344
2345       if(hasMaxMin && parent)
2346       {
2347          SkinBitmap skin;
2348          unichar symbol;
2349          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2350          if (state == minimized) 
2351          {
2352             skin = restore;
2353             method = RestoreButtonClicked;
2354             symbol = '\x12';
2355          }
2356          else
2357          {
2358             skin = minimize;
2359             method = MinimizeButtonClicked;
2360             symbol = '\x19';
2361          }
2362          if(!sysButtons[0])
2363          {
2364             sysButtons[0] =
2365                Button
2366                {
2367                   parent, master = this,
2368                   hotKey = altM, inactive = true, nonClient = true, visible = false
2369                };
2370             sysButtons[0].Create();
2371          }
2372          sysButtons[0].NotifyClicked = method;
2373
2374          sysButtons[0].symbol = symbol;
2375          sysButtons[0].disabled = !style.hasMinimize;
2376       }
2377
2378       // Create the scrollbars
2379       if(style.hasHorzScroll && !sbh)
2380       {
2381          sbh =
2382             ScrollBar
2383             {
2384                this,
2385                direction = horizontal,
2386                windowOwned = true,
2387                inactive = true,
2388                nonClient = true,
2389                snap = scrollFlags.snapX,
2390                NotifyScrolling = ScrollBarNotification
2391             };
2392          sbh.Create();
2393          scrollBarChanged = true;
2394       }
2395       else if(sbh && !style.hasHorzScroll)
2396       {
2397          sbh.Destroy(0);
2398          sbh = null;
2399       }
2400
2401       if(style.hasVertScroll && !sbv)
2402       {
2403          sbv =
2404             ScrollBar
2405             {
2406                this,
2407                direction = vertical,
2408                windowOwned = true,
2409                inactive = true,
2410                nonClient = true,
2411                snap = scrollFlags.snapY,
2412                NotifyScrolling = ScrollBarNotification
2413             };
2414          sbv.Create();
2415          scrollBarChanged = true;
2416       }
2417       else if(sbv && !style.hasVertScroll)
2418       {
2419          sbv.Destroy(0);
2420          sbv = null;
2421       }
2422       if(scrollBarChanged)
2423       {
2424          SetScrollLineStep(sbStep.x, sbStep.y);   
2425          UpdateScrollBars(true, true);
2426       }   
2427       UpdateNonClient();
2428
2429       if(scrollBarChanged)
2430       {
2431          if(sbh) sbh.thumbPosition = scroll.x;
2432          if(sbv) sbv.thumbPosition = scroll.y;
2433       }
2434    }
2435
2436    void UpdateCaption(void)
2437    {
2438       if(rootWindow == this)
2439       {
2440          char caption[2048];
2441          FigureCaption(caption);
2442          guiApp.interfaceDriver.SetRootWindowCaption(this, caption);
2443       }
2444       UpdateDecorations();
2445       if(parent)
2446       {
2447          if(parent.activeClient == this) // Added this last check
2448          {
2449             if(parent.rootWindow == parent)
2450             {
2451                char caption[2048];
2452                parent.FigureCaption(caption);
2453                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
2454             }
2455             else
2456                parent.UpdateCaption();
2457          }
2458          parent.UpdateDecorations();
2459       }
2460    }
2461
2462    void UpdateActiveDocument(Window previous)
2463    {
2464       Window activeClient = this.activeClient;
2465       Window activeChild = this.activeChild;
2466       if(menuBar)
2467       {
2468          UpdateCaption();
2469          if(!destroyed)
2470          {
2471             if(activeClient)
2472                activeClient.CreateSystemChildren();
2473             if(previous)
2474                previous.CreateSystemChildren();
2475          }
2476       }
2477
2478       if(menu)
2479       {
2480          MenuItem item;
2481          bool disabled;
2482
2483          if(menu)
2484             menu.Clean(this);
2485
2486          // Build window list
2487          if(activeClient)
2488          {
2489             Menu windowMenu = menu.FindMenu("Window");
2490             if(windowMenu)
2491             {
2492                OldLink cycle;
2493                int id;
2494                for(id = 0, cycle = activeClient.cycle; cycle && id<10;)
2495                {
2496                   MenuItem item;
2497                   Window document = cycle.data;
2498                   if(!document.style.nonClient && document.style.isActiveClient && document.visible)
2499                   {
2500                      char name[2048], caption[2048];
2501                      document.FigureCaption(caption);
2502                      sprintf(name, "%d %s", id+1, caption);
2503                      windowMenu.AddDynamic(MenuItem 
2504                         { 
2505                            copyText = true, text = name, hotKey = Key { k1 + id }, id = id++, 
2506                            NotifySelect = MenuWindowSelectWindow 
2507                         }, this, false);
2508                   }
2509                   cycle = cycle.next;
2510                   if(activeClient.cycle == cycle) break;
2511                }
2512             }
2513          }
2514          
2515          if((!previous && activeClient) || !activeClient)
2516          {
2517             if(!activeClient)
2518                disabled = true;
2519             else
2520                disabled = false;
2521             item = menu.FindItem(MenuWindowCloseAll, 0);
2522             if(item) item.disabled = false;
2523             item = menu.FindItem(MenuWindowNext, 0);
2524             if(item) item.disabled = false;
2525             item = menu.FindItem(MenuWindowPrevious, 0);
2526             if(item) item.disabled = false;
2527             item = menu.FindItem(MenuWindowCascade, 0);
2528             if(item) item.disabled = false;
2529             item = menu.FindItem(MenuWindowTileHorz, 0);
2530             if(item) item.disabled = false;
2531             item = menu.FindItem(MenuWindowTileVert, 0);
2532             if(item) item.disabled = false;
2533             item = menu.FindItem(MenuWindowArrangeIcons, 0);
2534             if(item) item.disabled = false;
2535             item = menu.FindItem(MenuWindowWindows, 0);
2536             if(item) item.disabled = false;
2537          }      
2538
2539          item = menu.FindItem(MenuFileClose, 0);
2540          if(item) item.disabled = !activeClient || !activeClient.style.hasClose;
2541          item = menu.FindItem(MenuFileSaveAll, 0);
2542          if(item) item.disabled = numDocuments < 1;
2543
2544          if(activeClient && activeClient.menu && activeClient.state != minimized)
2545          {
2546             if(mergeMenus)
2547             {
2548                //activeClient.menu.Clean(activeClient);
2549                menu.Merge(activeClient.menu, true, activeClient);
2550             }
2551          }
2552
2553          if(activeChild && activeChild != activeClient && activeChild.menu && activeChild.state != minimized)
2554          {
2555             if(mergeMenus)
2556                menu.Merge(activeChild.menu, true, activeChild);
2557          }
2558       }
2559       // This is called again for a child window change, with same active client
2560       OnActivateClient(activeClient, previous);
2561       if(!menuBar && !((BorderBits)borderStyle).fixed && parent && parent.activeClient == this)
2562          parent.UpdateActiveDocument(null);
2563    }
2564
2565    void _ShowDecorations(Box box, bool post)
2566    {
2567       if(rootWindow == this && nativeDecorations) return;
2568       if(visible && this != guiApp.desktop)
2569       {
2570          Surface surface = RedrawFull(box);
2571          if(surface)
2572          {
2573             char caption[2048];
2574             FigureCaption(caption);
2575             
2576             if(post)
2577                ShowDecorations(captionFont.font,
2578                   surface,
2579                   caption,
2580                   active, //parent.activeClient == this
2581                   guiApp.windowMoving == this);
2582             else
2583                PreShowDecorations(captionFont.font,
2584                   surface,
2585                   caption,
2586                   active, //parent.activeClient == this
2587                   guiApp.windowMoving == this);
2588                
2589             delete surface;
2590          }
2591       }
2592    }
2593
2594    void UpdateExtent(Box refresh)
2595    {
2596       Surface surface = null;
2597
2598       if(!manageDisplay) { OnRedraw(null);return; }
2599       _ShowDecorations(refresh, false);
2600
2601       surface = Redraw(refresh);               
2602       // Opaque background: just fill before EW_REDRAW (clear?)
2603       if(surface) 
2604       {
2605          surface.SetBackground(background);
2606          surface.SetForeground(foreground);
2607          surface.DrawingChar(' ');
2608          if(this == rootWindow)
2609          {
2610             if(style.drawBehind || background.a)
2611             {
2612                int a = background.a;
2613                // Premultiply alpha for clear color
2614                surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } });
2615                surface.Clear(colorBuffer);
2616                surface.SetBackground(background);
2617             }
2618          }
2619          else if(background.a)
2620          {
2621 #ifdef _DEBUG
2622             /*
2623             background.color = { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
2624             surface.SetForeground((background.color.r > 128 || background.color.g > 128) ? black : white);
2625             */
2626 #endif
2627             if(display.flags.alpha && background.a < 255 && background)
2628             {
2629                surface.Area(0,0,clientSize.w, clientSize.h);
2630                /*if(style.clearDepthBuffer)
2631                   surface.Clear(depthBuffer);*/
2632             }
2633             else if(/*style.clearDepthBuffer || */background.a)
2634             {
2635                int a = background.a;
2636                // surface.Clear((style.clearDepthBuffer ? depthBuffer : 0) | (background.a ? colorBuffer : 0));
2637                // Premultiply alpha for clear color
2638                surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } });
2639                surface.Clear(colorBuffer);
2640                surface.SetBackground(background);
2641             }
2642          }
2643
2644          // Default Settings
2645          surface.TextFont(usedFont.font);
2646          surface.TextOpacity(false);
2647
2648          OnRedraw(surface);
2649
2650          // Draw the caret ...
2651          if(!disabled && this == guiApp.caretOwner && guiApp.caretEnabled /*&& !guiApp.interimWindow*/ && !guiApp.currentSkin.textMode)
2652          {
2653             // surface.SetBackground(0xFFFFFF - background.color);
2654             surface.SetBackground(~background.color);
2655             surface.Area(
2656                caretPos.x - scroll.x + 1, caretPos.y - scroll.y,
2657                caretPos.x - scroll.x + 2, caretPos.y - scroll.y + caretSize - 1);
2658          }
2659          delete surface;
2660       }
2661    }
2662
2663    void DrawOverChildren(Box refresh)
2664    {
2665       Surface surface = Redraw(refresh);               
2666       if(surface) 
2667       {
2668          // Default Settings
2669          surface.DrawingChar(' ');
2670          surface.SetBackground(background);
2671          surface.SetForeground(foreground);
2672
2673          surface.TextFont(usedFont.font);
2674          surface.TextOpacity(false);
2675
2676          OnDrawOverChildren(surface);
2677
2678          delete surface;
2679
2680       }
2681       _ShowDecorations(refresh, true);
2682    }
2683
2684    void ComputeClipExtents(void)
2685    {
2686       Window child;
2687       Extent clipExtent { /*first = -1, last = -1, free = -1*/ };
2688
2689       clipExtent.Copy(this.clipExtent);
2690       
2691       for(child = children.last; child; child = child.prev)
2692       {
2693          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2694          {
2695             bool opaque = child.IsOpaque(); // TODO: acess background directly 
2696             int dx = child.absPosition.x - absPosition.x, dy = child.absPosition.y - absPosition.y;
2697
2698             child.clipExtent.Copy(clipExtent);
2699             child.clipExtent.Offset(-dx, -dy);
2700             child.clipExtent.IntersectBox(child.box);
2701
2702             child.ComputeClipExtents();
2703
2704             if(opaque && !child.style.nonClient)
2705             {
2706                // Adjust the box for the parent:
2707                Box box { child.box.left + dx, child.box.top + dy, child.box.right + dx, child.box.bottom + dy };
2708                clipExtent.ExcludeBox(box, rootWindow.tempExtents[0]);
2709             }
2710             
2711          }
2712       }
2713       // ??? Only do this for overlapped window or if parent has with clip children flag
2714
2715       // Do this if window has clip children flag on (default false?)
2716       // this.clipExtent = clipExtent;
2717
2718       clipExtent.Free(null);
2719    }
2720
2721    void ComputeRenderAreaNonOpaque(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2722    {
2723       bool opaque = IsOpaque();
2724       Window child;
2725       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2726       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2727       {
2728          offsetX -= rootWindow.clientStart.x;
2729          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2730       }
2731
2732
2733       for(child = children.last; child; child = child.prev)
2734       {
2735          ColorAlpha background = *(ColorAlpha *)&child.background;
2736          bool opaque = child.IsOpaque();
2737          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2738          {
2739             if(!opaque)
2740             {
2741                // Adjust renderArea to the root window level
2742                Extent * renderArea = &rootWindow.tempExtents[3];
2743
2744                int offsetX = child.absPosition.x - rootWindow.absPosition.x;
2745                int offsetY = child.absPosition.y - rootWindow.absPosition.y;
2746                if(child.rootWindow.nativeDecorations && rootWindow.windowHandle)
2747                {
2748                   offsetX -= child.rootWindow.clientStart.x;
2749                   offsetY -= child.rootWindow.clientStart.y - (child.rootWindow.hasMenuBar ? skinMenuHeight : 0);
2750                }
2751
2752                /*
2753                Extent childRenderArea;
2754                
2755                if(backBufferUpdate != null)
2756                {
2757                   childRenderArea.Copy(backBufferUpdate);
2758                   childRenderArea.Offset(-offsetX, -offsetY);
2759                }
2760                else
2761                   childRenderArea.Copy(child.dirtyArea);
2762
2763                // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2764                renderArea.Copy(dirtyExtent);
2765                renderArea.Offset(-offsetX, -offsetY);
2766                childRenderArea.Union(renderArea);
2767                renderArea.Free();
2768
2769                // Intersect with the clip extent
2770                childRenderArea.Intersection(child.clipExtent);
2771                */
2772
2773                renderArea->Copy(child.dirtyArea /*childRenderArea*/);
2774
2775                // This intersection with child clip extent was missing and causing #708 (Installer components list scrolling bug):
2776                renderArea->Intersection(child.clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2777
2778                renderArea->Offset(offsetX, offsetY);
2779
2780                dirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2781                // overDirtyExtent.Union(renderArea);
2782                renderArea->Empty();
2783                // childRenderArea.Free();
2784
2785                //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2786             }
2787          }
2788       }
2789
2790       for(child = children.last; child; child = child.prev)
2791       {
2792          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2793          {
2794             child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2795          }
2796       }
2797    }
2798
2799    void ComputeRenderArea(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2800    {
2801       bool opaque = IsOpaque();
2802       Extent * dirtyExtentWindow = &rootWindow.tempExtents[1];
2803       Window child;
2804       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2805       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2806       {
2807          offsetX -= rootWindow.clientStart.x;
2808          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2809       }
2810
2811 #if 0
2812       for(child = children.last; child; child = child.prev)
2813       {
2814          //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2815          /*
2816          ColorAlpha background = *(ColorAlpha *)&child.background;
2817          bool opaque = child.IsOpaque();
2818          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2819          {
2820             if(!opaque)
2821             {
2822                int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y;
2823                // Adjust renderArea to the root window level
2824                Extent renderArea;
2825                renderArea.Copy(child.dirtyArea);
2826                renderArea.Offset(offsetX, offsetY);
2827                dirtyExtent.Union(renderArea);
2828                overDirtyExtent.Union(renderArea);
2829                renderArea.Free();
2830             }
2831          }*/
2832       }
2833 #endif
2834       for(child = children.last; child; child = child.prev)
2835       {
2836          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2837          {
2838             child.ComputeRenderArea(dirtyExtent, overDirtyExtent, backBufferUpdate);
2839          }
2840       }
2841
2842       if(backBufferUpdate != null)
2843       {
2844          renderArea.Copy(backBufferUpdate);
2845          renderArea.Offset(-offsetX, -offsetY);
2846          
2847          overRenderArea.Copy(backBufferUpdate);
2848          overRenderArea.Offset(-offsetX, -offsetY);
2849          
2850          
2851       }
2852       else
2853       {
2854          renderArea.Copy(dirtyArea);
2855          
2856          overRenderArea.Copy(dirtyArea);
2857       }
2858
2859       // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2860       dirtyExtentWindow->Copy(dirtyExtent);
2861       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2862       renderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2863       dirtyExtentWindow->Empty();
2864
2865       // Intersect with the clip extent
2866       renderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2867
2868       /*
2869       if(renderArea.count > 10)
2870       {
2871          BoxItem extentBox;
2872          printf("\nToo many extents (%d):\n", renderArea.count);
2873
2874          //extent.UnionBox({ 112, 6, 304, 7 }, rootWindow.tempExtents[0]);
2875          //extent.UnionBox({ 112, 8, 304, 17 }, rootWindow.tempExtents[0]);
2876          //printf("Test\n");
2877
2878          {
2879             int c;
2880             for(c = 0; c<10; c++)
2881             {
2882                Extent extent { };
2883                FASTLIST_LOOP(renderArea, extentBox)
2884                {
2885                   extent.UnionBox(extentBox.box, rootWindow.tempExtents[0]);
2886                }
2887                renderArea.Copy(extent);
2888
2889                FASTLIST_LOOP(renderArea, extentBox)
2890                {
2891       #ifdef _DEBUG
2892                   printf("(%d, %d) - (%d, %d)\n", 
2893                      extentBox.box.left, extentBox.box.top, 
2894                      extentBox.box.right, extentBox.box.bottom);
2895       #endif
2896                }
2897
2898                printf("\nNow %d\n", renderArea.count);
2899             }
2900          }
2901       }
2902       */
2903       
2904       // WHY WAS THIS COMMENTED ??
2905
2906       // Add extent forced by DrawOverChildren to the dirty area, adjusting dirty extent to the window
2907       dirtyExtentWindow->Copy(overDirtyExtent);
2908       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2909       overRenderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2910       dirtyExtentWindow->Empty();
2911
2912       // Intersect with the clip extent
2913       overRenderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2914       
2915
2916       if(opaque)
2917       {
2918          // Scrolling
2919          if(scrollExtent.count)
2920          {
2921             // Subtract render extent from scrolling extent
2922             scrollExtent.Exclusion(renderArea, rootWindow.tempExtents[0]);
2923
2924             if(backBufferUpdate == null)
2925             {
2926                Extent * dirty = &rootWindow.tempExtents[3];
2927                BoxItem scrollBox;
2928
2929                // Intersect scrolling extent with clip extent
2930                scrollExtent.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2931
2932                // offset this scroll to be at the root window level
2933                scrollExtent.Offset(offsetX, offsetY);
2934                // Add area that was scrolled to the dirty extents of the back buffer
2935                rootWindow.dirtyBack.Union(scrollExtent, rootWindow.tempExtents[0]);
2936
2937                dirty->Empty();
2938
2939                // Will need scrolledArea.x & scrolledArea.y to support multiple scrolls
2940                for(scrollBox = (BoxItem)scrollExtent.first; scrollBox; scrollBox = (BoxItem)scrollBox.next)
2941                   display.Scroll(scrollBox.box, scrolledArea.x, scrolledArea.y, dirty);
2942
2943                scrolledArea.x = 0;
2944                scrolledArea.y = 0;
2945
2946                scrollExtent.Empty();
2947
2948                // Add the exposed extent to the window render area
2949                dirty->Offset(-offsetX, -offsetY);
2950                renderArea.Union(dirty, rootWindow.tempExtents[0]);
2951                dirty->Empty();
2952             }
2953          }
2954
2955          // Subtract the window's box from the transparency forced extent
2956          dirtyExtent.ExcludeBox({box.left + offsetX, box.top + offsetY, box.right + offsetX, box.bottom + offsetY }, rootWindow.tempExtents[0]);
2957       }
2958       /*else
2959       {
2960          Extent renderArea;
2961
2962          renderArea.Copy(this.renderArea);
2963          renderArea.Offset(offsetX, offsetY);
2964          dirtyExtent.Union(renderArea);
2965          renderArea.Free();
2966       }*/
2967       
2968       
2969       {
2970          Extent renderArea { };
2971          
2972          renderArea.Copy(overRenderArea);
2973          renderArea.Offset(offsetX, offsetY);
2974          overDirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2975          renderArea.Empty();
2976       }
2977       
2978
2979       if(backBufferUpdate != null)
2980       {
2981          // Remove render area from dirty area
2982          dirtyArea.Exclusion(renderArea, rootWindow.tempExtents[0]);
2983
2984          dirtyArea.Exclusion(overRenderArea, rootWindow.tempExtents[0]);
2985       }
2986       else
2987          dirtyArea.Empty();
2988
2989       clipExtent.Empty();
2990    /*
2991       // Remove the window render area from the dirty extents of the back buffer
2992       rootWindow.dirtyBack.Exclusion(renderArea);
2993    */
2994    }
2995
2996    void Render(Extent updateExtent)
2997    {
2998       BoxItem extentBox;
2999       Window child;
3000       Window rootWindow = this.rootWindow;
3001       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
3002       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
3003       {
3004          offsetX -= rootWindow.clientStart.x;
3005          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
3006       }
3007
3008       if(rootWindow.fullRender)
3009       {
3010          UpdateExtent(box);
3011          dirtyArea.Empty();
3012       }
3013       else
3014       {
3015 #ifdef _DEBUG
3016          /*
3017          background = Color { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
3018          foreground = (background.color.r > 128 || background.color.g > 128) ? black : white;
3019          */
3020 #endif
3021             
3022 #ifdef _DEBUG
3023          /*if(renderArea.count)
3024             printf("\n\nRendering %s (%x):\n------------------------------------------\n", _class.name, this);*/
3025 #endif
3026             
3027          for(extentBox = (BoxItem)renderArea.first; extentBox; extentBox = (BoxItem)extentBox.next)
3028          {
3029             Box box = extentBox.box;
3030
3031 #ifdef _DEBUG
3032                /*printf("(%d, %d) - (%d, %d)\n", 
3033                   extentBox.box.left, extentBox.box.top, 
3034                   extentBox.box.right, extentBox.box.bottom);*/
3035 #endif
3036                
3037             UpdateExtent(box);
3038
3039             box.left += offsetX;
3040             box.top += offsetY;
3041             box.right += offsetX;
3042             box.bottom += offsetY;
3043
3044             if(updateExtent != null)
3045                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
3046          }
3047       }
3048
3049       for(child = children.first; child; child = child.next)
3050          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && !child.nonClient)
3051             child.Render(updateExtent);
3052
3053       if(rootWindow.fullRender)
3054          DrawOverChildren(box);
3055       else
3056       {
3057          // TO DO: There's an issue about draw over children...
3058          // TO DO: Don't wanna go through this if method isn't used
3059          for(extentBox = (BoxItem)overRenderArea.first; extentBox; extentBox = (BoxItem)extentBox.next)
3060          //FASTLIST_LOOP(/*renderArea */overRenderArea, extentBox)
3061          {
3062             Box box = extentBox.box;
3063
3064             DrawOverChildren(box);
3065
3066             box.left += offsetX;
3067             box.top += offsetY;
3068             box.right += offsetX;
3069             box.bottom += offsetY;
3070
3071             if(updateExtent != null)
3072                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
3073          }
3074       }
3075       for(child = children.first; child; child = child.next)
3076          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && child.nonClient)
3077             child.Render(updateExtent);
3078
3079       renderArea.Empty();
3080       overRenderArea.Empty();
3081    }
3082
3083    public void UpdateDisplay(void)
3084    {
3085       if(!manageDisplay) { OnRedraw(null);return; }
3086       if(rootWindow && this != rootWindow) 
3087          rootWindow.UpdateDisplay();
3088       else if(display)
3089       {
3090          Extent dirtyExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that needs to be forced due to transparency
3091          Extent overExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that forced for DrawOverChildren
3092          BoxItem extentBox;
3093
3094          dirtyExtent.Clear();
3095          overExtent.Clear();
3096
3097          clipExtent.AddBox(box);
3098
3099          display.StartUpdate();
3100
3101          if(!rootWindow.fullRender)
3102          {
3103             ComputeClipExtents();
3104             ComputeRenderAreaNonOpaque(dirtyExtent, overExtent, null);
3105             ComputeRenderArea(dirtyExtent, overExtent, null);
3106          }
3107          else
3108             clipExtent.Free(null);                     
3109
3110          dirtyExtent.Free(null);
3111          overExtent.Free(null);
3112
3113          if(display.flags.flipping)
3114          {
3115             Render(null);
3116             display.Update(null);
3117          }
3118          else
3119          {
3120             Extent updateExtent { /*first = -1, last = -1, free = -1*/ }; // Extent that needs to be updated
3121             updateExtent.Clear();
3122
3123             Render(updateExtent);
3124             if(fullRender)
3125                updateExtent.UnionBox(this.box, tempExtents[0]);
3126             
3127 #ifdef _DEBUG
3128             //printf("\n\nUpdate:\n------------------------------------------\n");
3129 #endif
3130             
3131             //FASTLIST_LOOP(updateExtent, extentBox)
3132             for(extentBox = (BoxItem)updateExtent.first; extentBox; extentBox = (BoxItem)extentBox.next)
3133             {
3134 #ifdef _DEBUG
3135                /*printf("Updating (%d, %d) - (%d, %d)\n", 
3136                   extentBox.box.left, extentBox.box.top, 
3137                   extentBox.box.right, extentBox.box.bottom);*/
3138 #endif
3139                
3140                display.Update(extentBox.box);
3141                
3142             }
3143             updateExtent.Free(null);
3144          }
3145
3146          display.EndUpdate();
3147          dirtyBack.Empty();
3148
3149          dirty = false;
3150          resized = false;
3151       }
3152    }
3153
3154    void UpdateBackDisplay(Box box)
3155    {
3156       if(display)
3157       {
3158          Extent dirtyExtent;
3159          Extent overExtent;
3160          Extent intersection { /*first = -1, last = -1, free = -1*/ };
3161
3162          //printf("UpdateBackDisplay going through!\n");
3163          display.StartUpdate();
3164
3165          if(resized)
3166          {
3167             intersection.Copy(dirtyBack);
3168             intersection.IntersectBox(box);
3169          
3170             dirtyExtent.Clear();
3171             overExtent.Clear();
3172
3173             clipExtent.AddBox(box);
3174          
3175             if(!rootWindow.fullRender)
3176             {
3177                ComputeClipExtents();
3178                ComputeRenderArea(dirtyExtent, overExtent, intersection);
3179             }
3180             else
3181                clipExtent.Free(null);
3182
3183             intersection.Free(null);
3184             dirtyExtent.Free(null);
3185             overExtent.Free(null);
3186
3187             Render(null);
3188          }
3189
3190          if(display.flags.flipping)
3191             display.Update(null);
3192          else
3193          {
3194             rootWindow.display.Update(box);
3195          }
3196
3197          display.EndUpdate();
3198
3199          if(resized)
3200          {
3201             dirtyBack.ExcludeBox(box, rootWindow.tempExtents[0]);
3202             if(dirtyBack.count > MAX_DIRTY_BACK)
3203             {
3204                BoxItem extentBox, next;
3205                BoxItem first = (BoxItem)ACCESS_ITEM(dirtyBack, dirtyBack.first);
3206                for(extentBox = (BoxItem)dirtyBack.first; extentBox; extentBox = next)
3207                {
3208                   next = (BoxItem)extentBox.next;
3209                   if(extentBox != first)
3210                   {
3211                      if(extentBox.box.left < first.box.left)
3212                         first.box.left = extentBox.box.left;
3213                      if(extentBox.box.top < first.box.top)
3214                         first.box.top = extentBox.box.top;
3215                      if(extentBox.box.right > first.box.right)
3216                         first.box.right = extentBox.box.right;
3217                      if(extentBox.box.bottom > first.box.bottom)
3218                         first.box.bottom = extentBox.box.bottom;
3219                      dirtyBack.Delete(extentBox);
3220                   }
3221                }
3222             }
3223             resized = false;
3224          }
3225       }
3226    }
3227
3228    // --- Window positioning ---
3229    // --- Window identification ---
3230
3231    // Returns window at position "Position"
3232    Window GetAtPosition(int x, int y, bool clickThru, bool acceptDisabled, Window last)
3233    {
3234       Window child, result = null;
3235       Box box = this.box;
3236       box.left += absPosition.x;
3237       box.right += absPosition.x;
3238       box.top += absPosition.y;
3239       box.bottom += absPosition.y;
3240
3241       if(!destroyed && visible && (acceptDisabled || !disabled))
3242       {
3243          int lx = x - absPosition.x;
3244          int ly = y - absPosition.y;
3245          if(IsInside(lx, ly))
3246          // if(box.IsPointInside(Point{x, y}))
3247          {
3248             if(!clickThru || !style.clickThrough) result = (this == last) ? null : this;
3249             // If the window is disabled, stop looking in children (for acceptDisabled mode)
3250             if(!disabled)
3251             {
3252                bool isD = (last && last != this && last.IsDescendantOf(this)); //  Fix for WSMS (#844)
3253                Window ancestor = null;
3254                if(isD)
3255                   for(ancestor = last; ancestor && ancestor.parent != this; ancestor = ancestor.parent);
3256                // for(child = isD ? (last.previous == children.first ? null : last.previous) : children.last; child; child = child.prev)
3257                for(child = isD ? (ancestor.previous == children.first ? null : ancestor) : children.last; child; child = child.prev)
3258                {
3259                   if(child != statusBar && child.rootWindow == rootWindow)
3260                   {
3261                      Window childResult = child.GetAtPosition(x, y, clickThru, acceptDisabled, last);
3262                      if(childResult) 
3263                         return childResult;
3264                   }
3265                }
3266                if(clickThru)
3267                {
3268                   //for(child = isD ? (last.previous == children.first ? null : last.previous) : children.last; child; child = child.prev)
3269                   for(child = isD ? (ancestor.previous == children.first ? null : ancestor.previous) : children.last; child; child = child.prev)
3270                   {
3271                      if(child != statusBar && child.rootWindow == rootWindow)
3272                      {
3273                         Window childResult = child.GetAtPosition(x, y, false, acceptDisabled, last);
3274                         if(childResult)
3275                            return childResult;
3276                      }
3277                   }
3278                }
3279
3280                if(last && last != this && this.IsDescendantOf(last)) // Fix for installer lockup
3281                   result = null;
3282             }
3283          }
3284       }
3285       return result;
3286    }
3287
3288    Window FindModal(void)
3289    {
3290       Window modalWindow = this, check;
3291       Window check2 = null;
3292       for(check = this; check.master; check = check.master)
3293       {
3294          if(check.master.modalSlave && check.master.modalSlave.created && check != check.master.modalSlave)
3295          {
3296             modalWindow = check.master.modalSlave;
3297             check = modalWindow;
3298          }
3299          // TESTING THIS FOR DROPBOX...
3300          if(!rootWindow || !rootWindow.style.interim)
3301          {
3302             for(check2 = check; check2.activeChild; check2 = check2.activeChild)
3303             {
3304                if(check2.modalSlave && check2.modalSlave.created)
3305                {
3306                   modalWindow = check2.modalSlave;
3307                   break;
3308                }
3309             }
3310          }
3311       }
3312
3313       /*
3314       if(modalWindow == this)
3315       {
3316          for(check = this; check.activeChild; check = check.activeChild)
3317          {
3318             if(check.modalSlave)
3319             {
3320                modalWindow = check.modalSlave;
3321                break;
3322             }
3323          }
3324       }
3325       */
3326       for(; modalWindow.modalSlave && modalWindow.modalSlave.created; modalWindow = modalWindow.modalSlave);
3327       return (modalWindow == this || this == guiApp.interimWindow || IsDescendantOf(modalWindow)) ? null : modalWindow;
3328    }
3329
3330    void StopMoving(void)
3331    {
3332       if(this == guiApp.windowMoving)
3333       {
3334          guiApp.windowMoving = null;
3335          UpdateDecorations();
3336          SetMouseRange(null);
3337          if(rootWindow)
3338          {
3339             if(rootWindow.active)
3340                guiApp.interfaceDriver.StopMoving(rootWindow);
3341          }
3342          ReleaseCapture();
3343          guiApp.resizeX = guiApp.resizeY = guiApp.resizeEndX = guiApp.resizeEndY = false;
3344          guiApp.windowIsResizing = false;
3345       }
3346    }
3347
3348    void SelectMouseCursor(void)
3349    {
3350       int x,y;
3351       Window mouseWindow;
3352       Window modalWindow;
3353       Window cursorWindow = null;
3354       bool rx, ry, rex, rey;
3355
3356       guiApp.desktop.GetMousePosition(&x, &y);
3357       mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null;
3358
3359       if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling)
3360          guiApp.SetCurrentCursor(guiApp.systemCursors[moving]);
3361       else if(mouseWindow)
3362       {
3363          modalWindow = mouseWindow.FindModal();
3364          x -= mouseWindow.absPosition.x;
3365          y -= mouseWindow.absPosition.y;
3366          if(guiApp.windowIsResizing)
3367          {
3368             rex = guiApp.resizeEndX;
3369             rey = guiApp.resizeEndY;
3370             rx = guiApp.resizeX;
3371             ry = guiApp.resizeY;
3372             if((rex && rey) || (rx && ry))
3373                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3374             else if((rex && ry) || (rx && rey))
3375                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3376             else if((ry || rey) && (!rx && !rex))
3377                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3378             else if((rx || rex) && (!ry && !rey))
3379                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3380          }
3381          else if(!modalWindow && !guiApp.windowCaptured &&
3382             mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h,
3383                &rx, &ry, &rex, &rey))
3384          {
3385             if((rex && rey) || (rx && ry))
3386                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3387             else if((rex && ry) || (rx && rey))
3388                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3389             else if((ry || rey) && (!rx && !rex))
3390                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3391             else if((rx || rex) && (!ry && !rey))
3392                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3393          }
3394          else if(!guiApp.windowCaptured && !modalWindow && !guiApp.interimWindow)
3395          {
3396             if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}))
3397                cursorWindow = mouseWindow.parent;
3398             else
3399                cursorWindow = mouseWindow;
3400          }
3401          else if(!guiApp.interimWindow)
3402             cursorWindow = guiApp.windowCaptured;
3403          if(cursorWindow)
3404          {
3405             for(; !cursorWindow.cursor && !cursorWindow.style.nonClient; cursorWindow = cursorWindow.parent);
3406             guiApp.SetCurrentCursor(cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
3407          }
3408          else if(modalWindow)
3409          {
3410             guiApp.SetCurrentCursor(guiApp.systemCursors[arrow]);
3411          }
3412          else if(guiApp.interimWindow)
3413          {
3414             if(guiApp.interimWindow.cursor)
3415                guiApp.SetCurrentCursor(guiApp.interimWindow.cursor);
3416             else
3417                guiApp.SetCurrentCursor(mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
3418          }
3419       }
3420    }
3421
3422    // --- State based input ---
3423    bool AcquireInputEx(bool state)
3424    {
3425       bool result;
3426       if(state) 
3427       {
3428          guiApp.interfaceDriver.GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY);
3429          guiApp.interfaceDriver.SetMousePosition(clientSize.w/2 + absPosition.x, clientSize.h/2 + absPosition.y);
3430       }
3431       result = guiApp.interfaceDriver.AcquireInput(rootWindow, state);
3432       if(result)
3433          guiApp.acquiredWindow = state ? this : null;
3434       if(state && result)
3435       {
3436          SetMouseRangeToClient();
3437          guiApp.interfaceDriver.SetMouseCursor((SystemCursor)-1);
3438       }
3439       else
3440       {
3441          FreeMouseRange();
3442          SelectMouseCursor();
3443       }
3444       if(!state) guiApp.interfaceDriver.SetMousePosition(guiApp.acquiredMouseX, guiApp.acquiredMouseY);
3445       return result;
3446    }
3447
3448    // --- Window activation ---
3449    bool PropagateActive(bool active, Window previous, bool * goOnWithActivation, bool direct)
3450    {
3451       bool result = true;
3452       if(!parent || !parent.style.inactive)
3453       {
3454          Window parent = this.parent;
3455
3456          /*
3457          if(rootWindow == this)
3458             Log(active ? "active\n" : "inactive\n");
3459          */
3460
3461          // Testing this here...
3462          if(!parent || parent == guiApp.desktop || parent.active)
3463          {
3464             this.active = active;
3465          }
3466
3467          // TESTING THIS HERE
3468          UpdateDecorations();
3469          if(result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master)
3470             result = NotifyActivate(master, this, active, previous);
3471          else
3472          {
3473             this.active = !active;
3474          }
3475
3476          if(result)
3477          {
3478             if(!parent || parent == guiApp.desktop || parent.active)
3479             {
3480                this.active = active;
3481                if(acquiredInput)
3482                   AcquireInputEx(active);
3483                if(active)
3484                {
3485                   if(caretSize)
3486                   {
3487                      if(guiApp.caretOwner)
3488                      {
3489                         Box extent 
3490                         {
3491                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1, 
3492                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + 1,
3493                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2, 
3494                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + guiApp.caretOwner.caretSize - 1
3495                         };
3496                         guiApp.caretOwner.Update(extent);
3497                      }
3498
3499                      if(visible || !guiApp.caretOwner)
3500                         guiApp.caretOwner = this;
3501                      UpdateCaret(false, false);
3502                   }
3503                }
3504             }
3505             else
3506             {
3507                this.active = false;
3508                if(acquiredInput)
3509                   AcquireInputEx(active);
3510             }
3511             if(!active && guiApp.caretOwner == this)
3512             {
3513                UpdateCaret(false, true);
3514                guiApp.caretOwner = null;
3515                guiApp.interfaceDriver.SetCaret(0,0,0);
3516                guiApp.caretEnabled = false;
3517             }
3518
3519             if(!style.interim)
3520             {
3521                if(!active && parent && parent.activeChild && parent.activeChild != this)
3522                   if(!parent.activeChild.PropagateActive(false, previous, goOnWithActivation, true) || !*goOnWithActivation)
3523                   {
3524                      return false;
3525                   }
3526             }
3527
3528             if(!active && menuBar)
3529             {
3530                bool goOn;
3531                menuBar.OnActivate(false, null, &goOn, true);
3532                menuBar.NotifyActivate(menuBar.master, menuBar, false, null);
3533             }
3534
3535             if(activeChild)
3536             {
3537                Window aChild = activeChild;
3538                incref aChild;
3539                if(!aChild.PropagateActive(active, previous, goOnWithActivation, false) || !*goOnWithActivation)
3540                {
3541                   delete aChild;
3542                   return false;
3543                }
3544                delete aChild;
3545             }
3546          }
3547       }
3548       return result;
3549    }
3550
3551    void ConsequentialMouseMove(bool kbMoving)
3552    {
3553       if(rootWindow)
3554       {
3555          if(kbMoving || !guiApp.windowMoving)
3556          {
3557             Modifiers mods {};
3558             int x,y;
3559             if(rootWindow == guiApp.desktop || rootWindow.parent == guiApp.desktop)
3560             {
3561                guiApp.interfaceDriver.GetMousePosition(&x, &y);
3562
3563                if(guiApp.windowMoving || rootWindow.GetAtPosition(x, y, true, false, null))
3564                   rootWindow.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &mods, true, false);
3565             }
3566          }
3567       }
3568    }
3569
3570    bool IsDescendantOf(Window ancestor)
3571    {
3572       Window window;
3573       for(window = this; window && window != ancestor; window = window.parent);
3574       return window == ancestor;
3575    }
3576
3577    bool IsSlaveOf(Window master)
3578    {
3579       Window window;
3580       for(window = this; window && window != master; window = window.master);
3581       return window == master;
3582    }
3583
3584    bool ActivateEx(bool active, bool activateParent, bool moveInactive, bool activateRoot, Window external, Window externalSwap)
3585    {
3586       bool result = true;
3587
3588       if(this && !destroyed /*&& state != Hidden*/)
3589       {
3590          Window swap = externalSwap;
3591
3592          incref this;
3593
3594          if(parent)
3595          {
3596             if(!active)
3597                StopMoving();
3598             if(activateParent && 
3599                (parent.activeChild != this || 
3600                (guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow))) &&
3601                active && _isModal &&
3602                parent != master && master)
3603                master.ActivateEx(true, true, false, activateRoot, external, externalSwap);
3604
3605             if(active)
3606             {
3607                if(parent)
3608                {
3609                   bool real = parent.activeChild != this;
3610
3611                   // TEST THIS: New activateParent check here!!! CAUSED MENUS NOT GOING AWAY
3612                   if(!style.inactive && /*activateParent && */guiApp.interimWindow && 
3613                      !IsDescendantOf(guiApp.interimWindow) && 
3614                      !IsSlaveOf(guiApp.interimWindow))
3615                   {
3616                      Window interimWindow = guiApp.interimWindow;
3617                      while(interimWindow && interimWindow != this)
3618                      {
3619                         Window master = interimWindow.master;
3620                         bool goOn = true;
3621                         guiApp.interimWindow = null;
3622                         if(guiApp.caretOwner)
3623                            guiApp.caretOwner.UpdateCaret(false, false);
3624
3625                         incref interimWindow;
3626                         if(!interimWindow.PropagateActive(false, this, &goOn, true))
3627                         {
3628                            result = false;
3629                            real = false;
3630                         }
3631                         delete interimWindow;
3632                         interimWindow = (master && master.style.interim) ? master : null;
3633                      }
3634                   }
3635                   if(style.interim)
3636                   {
3637                      guiApp.interimWindow = this;
3638                      /*guiApp.interfaceDriver.SetCaret(0,0,0);
3639                      guiApp.caretEnabled = false;*/
3640                      UpdateCaret(false, true);
3641                   }
3642
3643                   if(real)
3644                   {
3645                      bool acquireInput = false;
3646                      bool maximize =
3647                         parent.activeChild &&
3648                         parent.activeChild.state == maximized &&
3649                         parent != guiApp.desktop;
3650
3651                      if(!style.inactive) // (!style.isRemote || parent.active || parent.style.hidden))
3652                      {
3653                         if(!style.interim)
3654                         {
3655                            if(!swap && parent)
3656                               swap = parent.activeChild;
3657                            if(swap && swap.destroyed) swap = null;
3658                            if(swap && swap != this)
3659                            {
3660                               bool goOn = true;
3661                               if(!swap.PropagateActive(false, this, &goOn, true))
3662                                  swap = parent.activeChild;
3663                               if(!goOn)
3664                               {
3665                                  delete this;
3666                                  return false;
3667                               }
3668                            }
3669                            else
3670                               swap = null;
3671                         }
3672
3673                         if(!parent || parent.activeChild != this || style.interim)
3674                         {
3675                            bool goOn = true;
3676                            result = PropagateActive(true, swap, &goOn, true);
3677                            if(!result && !goOn) 
3678                            {
3679                               delete this;
3680                               return false;
3681                            }
3682                            acquireInput = true;
3683                         }
3684                      }
3685
3686                      if(style.hasMaximize && parent != guiApp.desktop)
3687                      {
3688                         if(maximize)
3689                            SetState(maximized, false, 0);
3690                         else if(state != maximized)
3691                         {
3692                            Window child;
3693                            for(child = parent.children.first; child; child = child.next)
3694                            {
3695                               if(this != child && child.state == maximized)
3696                                  child.SetState(normal, false, 0);
3697                            }
3698                         }
3699                      }
3700                   }
3701                   if(result)
3702                   {
3703                      if(!style.inactive && !style.interim /*&& (!style.isRemote || parent.active || parent.style.hidden)*/)
3704                      {
3705                         Window previous = parent.activeClient;
3706                         parent.activeChild = this;
3707                         if(!style.nonClient /*&& style.isActiveClient*/)
3708                         {
3709                            if(!style.hidden)
3710                            {
3711                               if(style.isActiveClient)
3712                                  parent.activeClient = this;
3713                               // Moved UpdateActiveDocument inside hidden check
3714                               // To prevent activating previous window while creating a new one
3715                               // (It was messing up the privateModule in the CodeEditor)
3716                               parent.UpdateActiveDocument(previous);
3717                            }
3718                         }
3719                      }
3720                   }
3721
3722                   //if(!style.isRemote)
3723                   {
3724                      if(rootWindow != this)
3725                      {
3726                         if(activateParent && parent && !parent.active /*parent != parent.parent.activeChild*/)
3727                            parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap);
3728                      }
3729                      else if(!guiApp.fullScreenMode)
3730                      {
3731                         Window modalRoot = FindModal();
3732                         if(!modalRoot) modalRoot = this;
3733                         if(!modalRoot.isForegroundWindow)
3734                         {
3735                            modalRoot.isForegroundWindow = true;
3736                            // To check : Why is parent null?
3737                            if(activateRoot && modalRoot.parent && !modalRoot.parent.display && external != modalRoot)
3738                            {
3739                               guiApp.interfaceDriver.ActivateRootWindow(modalRoot);
3740                            }
3741                            modalRoot.isForegroundWindow = false;
3742                         }
3743                      }
3744                   }
3745                
3746                   if(result && real && (!style.inactive || moveInactive) && parent)
3747                   {
3748                      Window last = parent.children.last;
3749
3750                      if(!style.stayOnTop)
3751                         for(; last && last.style.stayOnTop; last = last.prev);
3752                      
3753                      parent.children.Move(this, last);
3754
3755                      // Definitely don't want that:   why not?
3756                      Update(null);
3757
3758                      if(order)
3759                         parent.childrenOrder.Move(order, parent.childrenOrder.last);
3760                   }
3761                }
3762             }
3763             else 
3764             {
3765                if(!parent || style.interim || (parent.activeChild == this && !style.inactive))
3766                {
3767                   bool goOn = true;
3768                   if(!style.interim)
3769                   {
3770                      if(parent)
3771                      {
3772                         parent.activeChild = null;
3773                         if(!style.nonClient /*&& style.isActiveClient*/)
3774                         {
3775                            Window previous = parent.activeClient;
3776                            if(style.isActiveClient)
3777                               parent.activeClient = null;
3778                            parent.UpdateActiveDocument(previous);
3779                         }
3780                      }
3781                   }
3782                   if(this == guiApp.interimWindow)
3783                   {
3784                      guiApp.interimWindow = null;
3785                      if(guiApp.caretOwner)
3786                         guiApp.caretOwner.UpdateCaret(false, false);
3787                   }
3788                   if(!PropagateActive(false, externalSwap, &goOn, true) || !goOn)
3789                   {
3790                      delete this;
3791                      return false;
3792                   }
3793                }
3794             }
3795             if(!active || !swap)
3796                UpdateDecorations();
3797             if(swap)
3798                swap.UpdateDecorations();
3799
3800             if(active && rootWindow != this)
3801                ConsequentialMouseMove(false);
3802          }
3803          delete this;
3804       }
3805       return true;
3806    }
3807
3808    // --- Input Messages ---
3809    void ::UpdateMouseMove(int mouseX, int mouseY, bool consequential)
3810    {
3811       static bool reEntrancy = false;
3812       if(reEntrancy) return;
3813
3814       reEntrancy = true;
3815
3816       guiApp.cursorUpdate = true;
3817       if(guiApp.windowScrolling && !consequential)
3818       {
3819          guiApp.windowScrolling.SetScrollPosition(
3820             (guiApp.windowScrolling.sbh) ? 
3821                (guiApp.windowScrollingBefore.x - mouseX + guiApp.windowScrollingStart.x) : 0,
3822             (guiApp.windowScrolling.sbv) ? 
3823                (guiApp.windowScrollingBefore.y - mouseY + guiApp.windowScrollingStart.y) : 0);
3824       }
3825       if(guiApp.windowMoving)
3826       {
3827          if(mouseX != guiApp.movingLast.x || mouseY != guiApp.movingLast.y)
3828          {
3829             Window window = guiApp.windowMoving;
3830             int rx, ry;
3831             int w = window.size.w;
3832             int h = window.size.h;
3833             int aw, ah;
3834             MinMaxValue ew, eh;
3835             int x, y;
3836
3837             rx = mouseX - guiApp.windowMovingStart.x;
3838             ry = mouseY - guiApp.windowMovingStart.y;
3839
3840             // Size
3841             window.GetDecorationsSize(&ew, &eh);
3842
3843             if(guiApp.windowIsResizing)
3844             {
3845                x = window.scrolledPos.x;
3846                y = window.scrolledPos.y;
3847
3848                if(guiApp.resizeX)
3849                {
3850                   aw = Max(guiApp.windowResizingBefore.w - rx,window.skinMinSize.w);
3851                   rx = guiApp.windowResizingBefore.w - aw;
3852                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3853                   w = guiApp.windowResizingBefore.w - rx;
3854                }
3855                if(guiApp.resizeY)
3856                {
3857                   ah = Max(guiApp.windowResizingBefore.h - ry,window.skinMinSize.h);
3858                   ry = guiApp.windowResizingBefore.h - ah;
3859                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3860                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3861                   h = guiApp.windowResizingBefore.h - ry;
3862                }
3863                if(guiApp.resizeEndX)
3864                {
3865                   w = guiApp.windowResizingBefore.w + rx;
3866                   w = Max(w,1-x);
3867                }
3868                if(guiApp.resizeEndY) h = guiApp.windowResizingBefore.h + ry;
3869
3870                w -= ew;
3871                h -= eh;
3872
3873                w = Max(w, 1);
3874                h = Max(h, 1);
3875
3876                w = Max(w, window.minSize.w);
3877                h = Max(h, window.minSize.h);
3878                w = Min(w, window.maxSize.w);
3879                h = Min(h, window.maxSize.h);
3880
3881                if(!window.OnResizing(&w, &h))
3882                {
3883                   w = window.clientSize.w;
3884                   h = window.clientSize.h;
3885                }
3886
3887                w = Max(w, window.skinMinSize.w);
3888                h = Max(h, window.skinMinSize.h);
3889
3890                w += ew;
3891                h += eh;
3892
3893                if(guiApp.textMode)
3894                {
3895                   SNAPDOWN(w, textCellW);
3896                   SNAPDOWN(h, textCellH);
3897                }
3898
3899                if(guiApp.resizeX)
3900                {
3901                   aw = Max(w,window.skinMinSize.w);
3902                   rx = guiApp.windowResizingBefore.w - aw;
3903                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3904                   w = guiApp.windowResizingBefore.w - rx;
3905                }
3906                if(guiApp.resizeY)
3907                {
3908                   ah = Max(h,window.skinMinSize.h);
3909                   ry = guiApp.windowResizingBefore.h - ah;
3910                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3911                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3912                   h = guiApp.windowResizingBefore.h - ry;
3913                }
3914             }
3915          
3916             // Position
3917             if(!guiApp.windowIsResizing || guiApp.resizeX)
3918                x = guiApp.windowMovingBefore.x + rx;
3919             if(!guiApp.windowIsResizing || guiApp.resizeY)
3920                y = guiApp.windowMovingBefore.y + ry;
3921
3922             if(!guiApp.windowIsResizing)
3923             {
3924                // Limit
3925                if(window.parent == guiApp.desktop && guiApp.virtualScreen.w)
3926                {
3927                   x = Min(x, (guiApp.virtualScreen.w + guiApp.virtualScreenPos.x) -1);
3928                   y = Min(y, (guiApp.virtualScreen.h + guiApp.virtualScreenPos.y) -1);
3929                   x = Max(x,-(w-1) + guiApp.virtualScreenPos.x);
3930                   y = Max(y,-(h-1) + guiApp.virtualScreenPos.y);
3931                }
3932                else
3933                {
3934                   x = Min(x, (window.parent.reqScrollArea.w ? window.parent.reqScrollArea.w : window.parent.clientSize.w) -1);
3935                   y = Min(y, (window.parent.reqScrollArea.h ? window.parent.reqScrollArea.h : window.parent.clientSize.h) -1);
3936                   x = Max(x,-(w-1));
3937                   y = Max(y,-(h-1));
3938                }
3939             }
3940
3941             if(!guiApp.windowIsResizing || (guiApp.resizeX || guiApp.resizeY))
3942             {
3943                if(!window.OnMoving(&x, &y, w, h))
3944                {
3945                   x = window.scrolledPos.x;
3946                   y = window.scrolledPos.y;
3947                }
3948             }
3949
3950             if(guiApp.textMode)
3951             {
3952                SNAPDOWN(x, textCellW);
3953                SNAPDOWN(y, textCellH);
3954             }
3955
3956             if(!window.style.nonClient)
3957             {
3958                if(!window.style.fixed /*|| window.style.isDocument*/)
3959                {
3960                   if(!window.style.dontScrollHorz)
3961                      x += window.parent.scroll.x;
3962                   if(!window.style.dontScrollVert)
3963                      y += window.parent.scroll.y;
3964                }
3965             }
3966
3967             // Break the anchors for moveable/resizable windows
3968             // Will probably cause problem with IDE windows... Will probably need a way to specify if anchors should break
3969             if(window.style.fixed) 
3970             {
3971                if(window.state == normal)
3972                {
3973                   window.normalAnchor = Anchor { left = x, top = y };
3974                   window.normalSizeAnchor = SizeAnchor { { w, h } };
3975                   window.anchored = false;
3976                }
3977             }
3978
3979             window.stateAnchor = Anchor { left = x, top = y };
3980             window.stateSizeAnchor = SizeAnchor { { w, h } };
3981
3982             window.Position(x, y, w, h, false, true, guiApp.windowIsResizing, guiApp.windowIsResizing, false, true);
3983             // TOCHECK: Investigate why the following only redraws the scrollbars
3984             //window.Position(x, y, w, h, false, true, true, true, false, true);
3985
3986             guiApp.movingLast.x = mouseX;
3987             guiApp.movingLast.y = mouseY;
3988          }
3989       }
3990       reEntrancy = false;
3991    }
3992
3993    public bool MouseMessage(uint method, int x, int y, Modifiers * mods, bool consequential, bool activate)
3994    {
3995       bool result = true;
3996       bool wasMoving = guiApp.windowMoving ? true : false;
3997       bool wasScrolling = guiApp.windowScrolling ? true : false;
3998       Window w = null;
3999       while(result && w != this)
4000       {
4001          Window msgWindow = GetAtPosition(x,y, false, true, w);
4002          Window trueWindow = GetAtPosition(x,y, false, false, w);
4003          bool windowDragged = false;
4004          Window window;
4005          delete w;
4006          w = msgWindow;
4007          if(w) incref w;
4008          window = (w && !w.disabled) ? w : null;
4009          
4010          if(trueWindow) incref trueWindow;
4011
4012          if(consequential) mods->isSideEffect = true;
4013
4014          UpdateMouseMove(x, y, consequential);
4015
4016          if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this))
4017          {
4018             if(!guiApp.windowCaptured.isEnabled)
4019                guiApp.windowCaptured.ReleaseCapture();
4020             else
4021                window = guiApp.windowCaptured;
4022          }
4023
4024          if(trueWindow && activate &&
4025             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
4026              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
4027              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
4028              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
4029          {
4030             if(mods->alt && !mods->ctrl && !mods->shift)
4031             {
4032                Window moved = trueWindow;
4033                for(moved = trueWindow; moved; moved = moved.parent)
4034                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
4035                      break;
4036                if(moved) 
4037                {
4038                   window = moved;
4039                   windowDragged = true;
4040
4041                   // Cancel the ALT menu toggling...
4042                   window.rootWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4043                }
4044             }
4045          }
4046
4047          if(window && activate &&
4048             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
4049              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
4050              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
4051              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
4052          {
4053             Window modalWindow = window.FindModal();
4054
4055             /*if(mods->alt && !mods->shift && !mods->ctrl)
4056             {
4057                Window moved = window;
4058                for(moved = window; moved; moved = moved.parent)
4059                   if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
4060                      break;
4061                if(moved) 
4062                {
4063                   window = moved;
4064                   windowDragged = true;
4065
4066                   // Cancel the ALT menu toggling...
4067                   window.rootWindow.KeyMessage(OnKeyDown, 0, 0);
4068                }
4069             }*/
4070
4071             if(!windowDragged)
4072             {
4073                Window activateWindow = modalWindow ? modalWindow : window;
4074                if(activateWindow && !activateWindow.isRemote)
4075                {
4076                   bool doActivation = true;
4077                   //bool needToDoActivation = false;
4078                   Window check = activateWindow;
4079
4080                   for(check = activateWindow; check && check != guiApp.desktop; check = check.parent)
4081                   {
4082                      if(!check.style.inactive)
4083                      {
4084                         //needToDoActivation = true;
4085                         if(check.active)
4086                            doActivation = false;
4087                         break;
4088                      }
4089                   }
4090                   /*
4091                   if(!needToDoActivation)
4092                      doActivation = false;
4093                   */
4094
4095                   if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) || 
4096                      (guiApp.interimWindow && !window.IsDescendantOf(guiApp.interimWindow)))
4097                   {
4098                      // Let the OnLeftButtonDown do the activating instead
4099                      if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4100                      {
4101                         window = null;
4102                         result = true;
4103                      }
4104                      else
4105                      //if(activate)
4106                      {
4107                         incref activateWindow;
4108                         if(!activateWindow.ActivateEx(true, true, false, true, null, null))
4109                         {
4110                            delete activateWindow;
4111                            delete trueWindow;
4112                            return false;
4113                         }
4114                         if(activateWindow._refCount == 1)
4115                         {
4116                            delete activateWindow;
4117                            delete trueWindow;
4118                            return false;
4119                         }
4120                         delete activateWindow;
4121                         // Trouble with clickThrough, siblings and activation (Fix for nicktick scrolling, siblings/activation endless loops, #844)
4122                         activate = false;
4123                      }
4124                      mods->isActivate = true;
4125                   }
4126                }
4127             }
4128             if(!modalWindow && window && !window.destroyed)
4129             {
4130                if(!guiApp.windowCaptured || windowDragged)
4131                {
4132                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown)
4133                   {
4134                      bool moving = ((window.state != maximized &&
4135                            window.IsMouseMoving(
4136                         x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4137                         || (guiApp.windowMoving && !guiApp.windowIsResizing);
4138
4139                      if(!moving && window.IsMouseResizing(
4140                         x - window.absPosition.x,
4141                         y - window.absPosition.y,
4142                         window.size.w, window.size.h,
4143                         &guiApp.resizeX, &guiApp.resizeY, &guiApp.resizeEndX, &guiApp.resizeEndY))
4144                      {
4145                         guiApp.windowIsResizing = true;
4146                         guiApp.windowResizingBefore.w = window.size.w;
4147                         guiApp.windowResizingBefore.h = window.size.h;
4148                      }
4149                      if(guiApp.windowIsResizing || windowDragged || moving)
4150                      {
4151                         window.Capture();
4152                         guiApp.windowMoving = window;
4153                         guiApp.windowMovingStart.x = guiApp.movingLast.x = x;
4154                         guiApp.windowMovingStart.y = guiApp.movingLast.y = y;
4155                         guiApp.windowMovingBefore.x = window.position.x;//s;
4156                         guiApp.windowMovingBefore.y = window.position.y;//s;
4157                         if(guiApp.windowMoving == guiApp.windowMoving.rootWindow)
4158                            guiApp.interfaceDriver.StartMoving(guiApp.windowMoving.rootWindow, 0,0,false);
4159                      }
4160                   }
4161                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown)
4162                   {
4163                      if(window.style.fixed &&
4164                         (windowDragged || 
4165                         window.IsMouseMoving(
4166                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4167                      {
4168                         window.ShowSysMenu(x, y);
4169                         result = false;
4170                      }
4171                   }
4172                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown)
4173                   {
4174                      if(window.sbv || window.sbh)
4175                      {
4176                         window.Capture();
4177                         guiApp.windowScrolling = window;
4178                         guiApp.windowScrollingStart.x = x;
4179                         guiApp.windowScrollingStart.y = y;
4180                         guiApp.windowScrollingBefore.x = window.scroll.x;
4181                         guiApp.windowScrollingBefore.y = window.scroll.y;
4182                      }
4183                   }
4184                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4185                   {
4186                      if(window.style.hasMaximize && 
4187                         window.IsMouseMoving( 
4188                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))
4189                      {
4190                         window.SetState(
4191                            (window.state == maximized) ? normal : maximized, false, *mods);
4192                         result = false;
4193                      }
4194                   }
4195                }
4196             }
4197             else
4198                window = null;
4199             if(guiApp.windowMoving) 
4200             {
4201                if(guiApp.windowMoving.parent)
4202                {
4203                   if(guiApp.windowMoving.style.nonClient)
4204                      guiApp.windowMoving.parent.SetMouseRangeToWindow();
4205                   else
4206                      guiApp.windowMoving.parent.SetMouseRangeToClient();
4207                }
4208                else
4209                   FreeMouseRange();
4210                window.UpdateDecorations();
4211             }
4212          }
4213          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp)
4214          {
4215             // Log("\n*** LEFT BUTTON UP ***\n");
4216             if(guiApp.windowMoving)
4217                guiApp.windowMoving.StopMoving();
4218          }
4219          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp)
4220          {
4221             if(guiApp.windowScrolling)
4222             {
4223                Window windowScrolling = guiApp.windowScrolling;
4224                guiApp.windowScrolling = null;
4225                windowScrolling.ReleaseCapture();
4226             }
4227          }
4228
4229          if(!result || (window && window.destroyed)) window = null;
4230
4231          if(window && window.FindModal())
4232             window = null;
4233
4234          if(trueWindow && trueWindow.FindModal())
4235             delete trueWindow;
4236          
4237          /*if(trueWindow)
4238             incref trueWindow;
4239          */
4240
4241          /*
4242          msgWindow = GetAtPosition(x,y, true, false);
4243          if(msgWindow)
4244             msgWindow.SelectMouseCursor();
4245          */
4246
4247          if(guiApp.windowCaptured || trueWindow)
4248          {
4249             Window prevWindow = guiApp.prevWindow;
4250             if(guiApp.prevWindow && trueWindow != guiApp.prevWindow)
4251             {
4252                guiApp.prevWindow.mouseInside = false;
4253                guiApp.prevWindow = null;
4254
4255                // Eventually fix this not to include captured?
4256                if(!prevWindow.OnMouseLeave(*mods))
4257                   result = false;
4258             }
4259             if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/)
4260             {
4261                Box box = trueWindow.box;
4262                box.left += trueWindow.absPosition.x;
4263                box.right += trueWindow.absPosition.x;
4264                box.top += trueWindow.absPosition.y;
4265                box.bottom += trueWindow.absPosition.y;
4266
4267                if(box.IsPointInside({x, y}) && trueWindow != /*guiApp.*/prevWindow /*!trueWindow.mouseInside*/)
4268                {
4269                   int overX = x - (trueWindow.absPosition.x + trueWindow.clientStart.x);
4270                   int overY = y - (trueWindow.absPosition.y + trueWindow.clientStart.y);
4271
4272                   overX = Max(Min(overX, 32767),-32768);
4273                   overY = Max(Min(overY, 32767),-32768);
4274
4275                   trueWindow.mouseInside = true;
4276                   if(!trueWindow.OnMouseOver(overX, overY, *mods))
4277                      result = false;
4278                }
4279             }
4280             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
4281                guiApp.prevWindow = trueWindow;
4282             else
4283                guiApp.prevWindow = null;
4284          }
4285          SelectMouseCursor();
4286
4287          if(window && !guiApp.windowMoving && !wasMoving && !wasScrolling)
4288          {
4289             int clientX = x - (window.absPosition.x + window.clientStart.x);
4290             int clientY = y - (window.absPosition.y + window.clientStart.y);
4291
4292             bool (* MouseMethod)(Window instance, int x, int y, Modifiers mods);
4293
4294             clientX = Max(Min(clientX, 32767),-32768);
4295             clientY = Max(Min(clientY, 32767),-32768);
4296
4297             MouseMethod = (void *)window._vTbl[method];
4298
4299             if(MouseMethod /*&& !consequential*/ && !window.disabled)
4300             {
4301                incref window;
4302                if(!MouseMethod(window, clientX, clientY, *mods))
4303                   result = false;
4304                delete window;
4305             }
4306          }
4307          delete trueWindow;
4308          /*
4309          if(result && w && w.clickThrough && w.parent)
4310             w = w.parent;
4311          else
4312             break;
4313          */
4314          if(!result || !w || !w.clickThrough)
4315             break;
4316       }
4317       delete w;
4318       return result;
4319    }
4320
4321    // --- Mouse cursor management ---
4322
4323    bool KeyMessage(uint method, Key key, unichar character)
4324    {
4325       bool status = true;
4326       if(!parent)
4327       {
4328          if(guiApp.interimWindow)
4329             this = guiApp.interimWindow;
4330       }
4331 #ifdef _DEBUG
4332       if((SmartKey)key != alt && (SmartKey)key != Key::control && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && parent && this != parent.menuBar)
4333          Print("");
4334 #endif
4335
4336       if(!style.inactive || rootWindow != this)
4337       {
4338          bool (*KeyMethod)(Window window, Key key, unichar ch) = (void *)_vTbl[method];
4339          Window modalWindow = FindModal();
4340          Window interimMaster = master ? master.rootWindow : null;
4341
4342          incref this;
4343
4344          if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4345             status = OnSysKeyDown(key, character);
4346          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4347             status = OnSysKeyHit(key, character);
4348          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4349             status = OnSysKeyUp(key, character);
4350          if(!status)
4351          {
4352             delete this;
4353             return true;
4354          }
4355
4356          // Process Key Message for Internal UI Keyboard actions
4357          if(status && !destroyed && menuBar && state != minimized)
4358          {
4359             // Disable the ALT
4360             if((SmartKey)key != alt) 
4361                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4362             if(menuBar.focus)
4363             {
4364                SmartKey sk = (SmartKey) key;
4365                if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt)
4366                {
4367                   status = menuBar.KeyMessage(method, key, character);
4368                   status = false;
4369                }
4370                else
4371                {
4372                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4373                      menuBar.OnKeyHit(escape, 0);
4374                }
4375                if(!menuBar.focus && guiApp.caretOwner)
4376                   guiApp.caretOwner.UpdateCaret(true, false);
4377             }
4378          }
4379          if(!destroyed && status)
4380          {
4381             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4382             {
4383                switch(key)
4384                {
4385                   case left: case up: case right: case down:
4386                      if(guiApp.windowMoving == this)
4387                      {
4388                         int step = 1; //8;
4389                         int w = guiApp.windowMoving.size.w;
4390                         int h = guiApp.windowMoving.size.h;
4391                         int x = guiApp.windowMoving.scrolledPos.x;
4392                         int y = guiApp.windowMoving.scrolledPos.y;
4393
4394                         if(guiApp.textMode)
4395                         {
4396                            if(key == down || key == up)
4397                               step = Max(step, textCellH);
4398                            else
4399                               step = Max(step, textCellW);
4400                         }
4401
4402                         if(guiApp.windowIsResizing)
4403                         {
4404                            switch(key)
4405                            {
4406                               case left: w-=step; break;
4407                               case right: w+=step; break;
4408                               case up: h-=step;   break;
4409                               case down: h+=step; break;
4410                            }
4411                         }
4412                         else
4413                         {
4414                            switch(key)
4415                            {
4416                               case left: x-=step; break;
4417                               case right: x+=step; break;
4418                               case up: y-=step;   break;
4419                               case down: y+=step; break;
4420                            }
4421                         }
4422
4423                         if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w;
4424                         if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h;
4425
4426                         if(!guiApp.windowIsResizing || guiApp.resizeX)
4427                            x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x;
4428                         else
4429                            x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x;
4430
4431                         if(!guiApp.windowIsResizing || guiApp.resizeY)
4432                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
4433                         else                           
4434                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
4435
4436                         guiApp.interfaceDriver.SetMousePosition(x, y);
4437                         ConsequentialMouseMove(true);
4438
4439                         status = false;
4440                      }
4441                      break;
4442                   case escape:
4443                   case enter:
4444                   case keyPadEnter:
4445                      if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4446                      {
4447                         guiApp.windowMoving.StopMoving();
4448                         ConsequentialMouseMove(false);
4449                   
4450                         status = false;
4451                      }
4452                      break;
4453                   case altSpace:
4454                      if(style.fixed)
4455                      {
4456                         ShowSysMenu(absPosition.x, absPosition.y);
4457                         status = false;
4458                      }
4459                      break;
4460                }
4461             }
4462          }
4463
4464          if(!destroyed && status && state != minimized)
4465          {
4466             // Process all the way down the children
4467             if(activeChild && !activeChild.disabled)
4468             {
4469                status = activeChild.KeyMessage(method, key, character);
4470             }
4471             if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) &&
4472                key.code != left && key.code != right && key.code != up && key.code != down)
4473             {
4474                status = activeClient.KeyMessage(method, key, character);
4475             }
4476
4477             // Default Control
4478             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4479             {
4480                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized)
4481                   // && defaultControl != activeChild)
4482                {
4483                   delete previousActive;
4484                   previousActive = activeChild;
4485                   if(previousActive) incref previousActive;
4486
4487                   ConsequentialMouseMove(false);
4488                   if((defaultControl.active ||
4489                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
4490                      defaultControl.KeyMessage(method, defaultKey, character);
4491                   status = false;                       
4492                }
4493             }
4494          }
4495
4496          if(!destroyed && status && (!modalWindow || this == guiApp.desktop))
4497          {
4498             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4499             {
4500                switch(key)
4501                {
4502                   case altMinus:
4503                      if(style.fixed)
4504                      {
4505                         ShowSysMenu(absPosition.x, absPosition.y);
4506                         status = false;
4507                      }
4508                      break;
4509                   //case f5:
4510                   /*
4511                   case shiftF5:
4512                      if(this != guiApp.desktop)
4513                      {
4514                         if(!guiApp.windowMoving && !guiApp.windowCaptured)
4515                         {
4516                            if(state != maximized && (key.shift ? style.sizeable : style.fixed))
4517                            {
4518                               MenuMoveOrSize(key.shift, true);
4519                               status = false;
4520                            }
4521                         }
4522                         else if(guiApp.windowMoving)
4523                         {
4524                            guiApp.windowMoving.StopMoving();
4525                            ConsequentialMouseMove(false);
4526                            status = false;
4527                         }
4528                      }
4529                      break;
4530                   */
4531                }
4532             }
4533             if(!destroyed && status && state != minimized)
4534             {
4535                if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4536                {
4537                   switch(key)
4538                   {
4539                      case tab: case shiftTab:
4540                      {
4541                         Window cycleParent = this;
4542                         if(this == guiApp.interimWindow && master && !master.style.interim && !cycleParent.style.tabCycle && master.parent)
4543                            cycleParent = master.parent;
4544                         
4545                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
4546                         {
4547                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
4548                            {
4549                               Window child = cycleParent.activeChild;
4550
4551                               // Scroll the window to include the active control
4552                               /*
4553                               if(cycleParent.sbh && !child.style.dontScrollHorz)
4554                               {
4555                                  if(child.scrolledPos.x < 0)
4556                                     cycleParent.sbh.Action(Position, 
4557                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
4558                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
4559                                     cycleParent.sbh.Action(Position,
4560                                        cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0);
4561                               }
4562                               if(cycleParent.sbv && !child.style.dontScrollVert)
4563                               {
4564                                  if(child.scrolledPos.y < 0)
4565                                     cycleParent.sbv.Action(Position, 
4566                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
4567                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
4568                                     cycleParent.sbv.Action(Position,
4569                                        cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0);
4570                               }
4571                               */
4572                               cycleParent.ConsequentialMouseMove(false);
4573                               status = false;
4574                            }
4575                         }
4576                         break;
4577                      }
4578                      case f6: case shiftF6:
4579                         if(!guiApp.windowMoving /*!guiApp.windowCaptured*/)
4580                         {
4581                            // NOT NEEDED... guiApp.windowMoving.ReleaseCapture();
4582                            if(parent == guiApp.desktop)
4583                               if(guiApp.desktop.CycleChildren(key.shift, true, false, true))
4584                               {
4585                                  status = false;
4586                                  break;
4587                               }
4588                            if(style.tabCycle)
4589                            {
4590                               delete this;
4591                               return true;
4592                            }
4593                            if(CycleChildren(key.shift, true, false, true))
4594                            {
4595                               status = false;
4596                               break;
4597                            }
4598                         }
4599                         break;
4600                      /*
4601                      // mIRC Style Window Shortcuts
4602                      case alt1: case alt2: case alt3: case alt4: case alt5:
4603                      case alt6: case alt7: case alt8: case alt9: case alt0:
4604                      {
4605                         if(numPositions)
4606                         {
4607                            Window document;
4608                            for(document = children.first; document; document = document.next)
4609                            {
4610                               if(document.style.isDocument && document.documentID - 1 == key.code - k1)
4611                               {
4612                                  if(document == activeChild)
4613                                  {
4614                                     if(document.state == minimized)
4615                                        document.SetState(normal, false, key);
4616                                     else
4617                                     {
4618                                        document.SetState(minimized, false, key);
4619                                        CycleChildren(false, true, false);
4620                                     }
4621                                  }
4622                                  else
4623                                  {
4624                                     if(activeChild.state == maximized && document.style.hasMaximize)
4625                                        document.SetState(maximized, false, key);
4626                                     else if(document.state == minimized)
4627                                        document.SetState(normal, false, key);
4628                                     document.Activate();
4629                                  }
4630                                  status = false;
4631                                  break;
4632                               }
4633                            }
4634                         }
4635                         break;            
4636                      }
4637                      */
4638                   }
4639                }
4640             }
4641          }
4642
4643          if(!destroyed && status)
4644          {
4645             if(state == minimized)
4646             {
4647                delete this;
4648                return true;
4649             }
4650             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4651             {
4652                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive)
4653                {
4654                   if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character))
4655                      previousActive.ActivateEx(true, false, false, true, null, null);
4656                   delete previousActive;
4657                   status = false;
4658                }
4659             }
4660          }
4661
4662          if(!destroyed && status)
4663          {
4664             status = ProcessHotKeys(method, key, character);
4665          }
4666          if(!destroyed && status && !modalWindow && state != minimized)
4667          {
4668             if(KeyMethod)
4669                status = KeyMethod(this, key, character);
4670             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4671                status = OnKeyHit(key, character);
4672             if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
4673             {
4674                bool result = false;
4675                switch(key)
4676                {
4677                   case ctrlUp: case ctrlDown:
4678                      if(sbv && !guiApp.windowScrolling)
4679                         result = sbv.Action((key == ctrlUp) ? up : down, 0, key);
4680                      break;
4681                   case wheelUp: case wheelDown:
4682                      if(sbv && !guiApp.windowScrolling)
4683                      {
4684                         result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key);
4685                         // Do we want to do a consequential move regardless of result in this case?
4686                         ConsequentialMouseMove(false);
4687                      }
4688                      break;
4689                   case ctrlPageUp: case ctrlPageDown:
4690                      if(sbh && !guiApp.windowScrolling)
4691                         result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key);
4692                      break;
4693                }
4694                if(result)
4695                {
4696                   ConsequentialMouseMove(false);
4697                   status = false;
4698                }
4699             }
4700          }
4701          if(status && !destroyed && menuBar && state != minimized)
4702             status = menuBar.KeyMessage(method, key, character);
4703
4704          if(style.interim && /*destroyed && */status && interimMaster)
4705          {
4706             // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped...
4707             status = interimMaster.KeyMessage(method, key, character);
4708          }
4709          delete this;
4710       }
4711       return status;
4712    }
4713
4714    bool ProcessHotKeys(uint method, Key key, unichar character)
4715    {
4716       bool status = true;
4717       HotKeySlot hotKey;
4718
4719       for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next)
4720          if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) &&
4721             !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized))
4722          {
4723             Window hotKeyWindow = hotKey.window;
4724             Window parent = hotKeyWindow.parent;
4725             Window prevActiveWindow = activeChild;
4726             // For when sys buttons are placed inside the menu bar
4727             if(parent && parent._class == class(PopupMenu))
4728                parent = parent.parent;
4729
4730             // 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
4731             if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || (hotKeyWindow != parent.sysButtons[2] && hotKeyWindow != parent.sysButtons[1])))
4732                continue;
4733
4734             if(prevActiveWindow) incref prevActiveWindow;
4735             incref hotKeyWindow;
4736             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient)
4737                if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null))
4738                {
4739                   status = false;
4740                   delete hotKeyWindow;
4741                   delete prevActiveWindow;
4742                   break;
4743                }
4744
4745             if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4746                method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
4747             if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character))
4748             {
4749                // *********   WORKING ON THIS   ***********
4750                if(prevActiveWindow && !guiApp.interimWindow)
4751                   prevActiveWindow.ActivateEx(true, false, false, false, null, null);
4752                status = false;
4753             }
4754             else if(hotKeyWindow.style.inactive)
4755                status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character);
4756
4757             delete prevActiveWindow;
4758             delete hotKeyWindow;
4759             // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key)
4760             if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4761                status = false;
4762             break;
4763          }
4764       if(status && tabCycle)
4765       {
4766          Window child;
4767          for(child = children.first; child; child = child.next)
4768          {
4769             if(child.tabCycle && !child.ProcessHotKeys(method, key, character))
4770             {
4771                status = false;
4772                break;
4773             }
4774          }
4775       }
4776       return status;
4777    }
4778
4779
4780    // --- Windows and graphics initialization / termination ---
4781    bool SetupRoot(void)
4782    {
4783       Window child;
4784
4785       // Setup relationship with outside world (bb root || !bb)
4786       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || 
4787          (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))
4788       {
4789          rootWindow = this;
4790          if(!tempExtents)
4791             tempExtents = new0 Extent[4];
4792          against = null;
4793       }
4794       else
4795       {
4796          /*if(guiApp.fullScreenMode)
4797             rootWindow = guiApp.desktop;
4798          else*/
4799          //rootWindow = parent.created ? parent.rootWindow : null;
4800          rootWindow = parent.rootWindow;
4801
4802          if(style.nonClient)
4803             against = &parent.box;
4804          else
4805             against = &parent.clientArea;
4806       }
4807
4808       for(child = children.first; child; child = child.next)
4809          child.SetupRoot();
4810
4811       return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false;
4812    }
4813
4814    bool Setup(bool positionChildren)
4815    {
4816       bool result = false;
4817       Window child;
4818
4819       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))))
4820       {
4821          subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
4822          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
4823
4824          windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
4825
4826          // This was here, is it really needed?
4827          //guiApp.interfaceDriver.ActivateRootWindow(this);
4828
4829          if(!displaySystem)
4830          {
4831             displaySystem = DisplaySystem {};
4832             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
4833             {
4834                delete displaySystem;
4835             }
4836          }
4837          if(displaySystem)
4838          {
4839             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
4840             if(display.Create(displaySystem, windowHandle))
4841                result = true;
4842             else
4843             {
4844                delete display;
4845             }
4846          }
4847          // Sometimes icon does not show up on Windows XP if we set here...
4848          // guiApp.interfaceDriver.SetIcon(this, icon);
4849       }
4850       else if(this != guiApp.desktop)
4851       {
4852          display = rootWindow ? rootWindow.display : null;
4853          result = true;
4854       }
4855       else
4856          result = true;
4857
4858       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
4859          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
4860
4861       for(child = children.first; child; child = child.next)
4862       {
4863          if(child.created && !child.Setup(false))
4864             result = false; 
4865       }
4866       return result;
4867    }
4868
4869    bool SetupDisplay(void)
4870    {
4871 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
4872       if(is3D) return Window3D_SetupDisplay(this); else 
4873 #endif   
4874       if(SetupRoot())
4875          return Setup(true);
4876       return false;
4877    }
4878
4879    class_data void ** pureVTbl;
4880
4881    bool LoadGraphics(bool creation, bool resetAnchors)
4882    {
4883       bool result = false;
4884       bool success = false;
4885       Window child;
4886       WindowState stateBackup = state;
4887
4888       if(((subclass(Window))_class).pureVTbl)
4889       {
4890          if(_vTbl == _class._vTbl)
4891          {
4892             _vTbl = ((subclass(Window))_class).pureVTbl;
4893          }
4894          else
4895          {
4896             int m;
4897             for(m = 0; m < _class.vTblSize; m++)
4898             {
4899                if(_vTbl[m] == _class._vTbl[m])
4900                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
4901             }
4902          }
4903       }
4904       if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
4905       {
4906          if(_vTbl == ((subclass(Window))_class).pureVTbl)
4907          {
4908             _vTbl = _class._vTbl;
4909          }
4910          else
4911          {
4912             int m;
4913             for(m = 0; m < _class.vTblSize; m++)
4914             {
4915                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
4916                   _vTbl[m] = _class._vTbl[m];
4917             }
4918          }
4919       }
4920       
4921       if(guiApp.fullScreenMode || this != guiApp.desktop)
4922       {
4923          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
4924          if(display)
4925          {
4926             ResPtr ptr;
4927             success = true;
4928
4929             display.Lock(false);
4930             if(rootWindow == this)
4931             {
4932                // Set Color Palette
4933                display.SetPalette(palette, true);
4934
4935                // Load Cursors
4936                /*
4937                if(guiApp.fullScreenMode && this == guiApp.desktop)
4938                {
4939                   int c;
4940                   Cursor cursor;
4941
4942                   for(c=0; c<SystemCursor::enumSize; c++)
4943                      if(!guiApp.systemCursors[c].bitmap)
4944                      {
4945                         guiApp.systemCursors[c].bitmapName = guiApp.currentSkin.CursorsBitmaps(c,
4946                            &guiApp.systemCursors[c].hotSpotX,&guiApp.systemCursors[c].hotSpotY, &guiApp.systemCursors[c].paletteShades);
4947                         if(guiApp.systemCursors[c].bitmapName)
4948                         {
4949                            guiApp.systemCursors[c].bitmap = eBitmap_LoadT(guiApp.systemCursors[c].bitmapName, null,
4950                               guiApp.systemCursors[c].paletteShades ? null : guiApp.desktop.display.displaySystem);
4951                            if(guiApp.systemCursors[c].bitmap)
4952                               guiApp.systemCursors[c].bitmap.paletteShades = guiApp.systemCursors[c].paletteShades;
4953                            else
4954                               success = false;
4955                         }
4956                      }
4957                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
4958                   {
4959                      cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null, 
4960                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
4961                      if(cursor.bitmap)
4962                         cursor.bitmap.paletteShades = cursor.paletteShades;
4963                      else
4964                         success = false;
4965                   }
4966                   guiApp.cursorUpdate = true;
4967
4968                   display.Unlock();
4969                   ConsequentialMouseMove(false);
4970                   display.Lock(true);
4971                }
4972                */
4973             }
4974
4975             // Load Window Graphic Resources
4976             
4977             /*
4978             if(usedFont == setFont || usedFont == window.systemFont)
4979                RemoveResource(usedFont);
4980             */
4981             if(setFont)
4982                RemoveResource(setFont); // TESTING setFont instead of usedFont);
4983
4984             if(systemFont)
4985                RemoveResource(systemFont);
4986             
4987             if(captionFont)
4988                RemoveResource(captionFont);
4989
4990             for(ptr = resources.first; ptr; ptr = ptr.next)
4991             {
4992                ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
4993             }
4994             if(setFont)
4995                AddResource(setFont);
4996             if(systemFont)
4997                AddResource(systemFont);
4998
4999             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
5000
5001             firewatchers font;
5002
5003             /*
5004             if(!setFont)
5005             {
5006                //if(master && master.font)
5007                if(parent && parent.font)
5008                {
5009                   font = FontResource
5010                   {
5011                      faceName = parent.font.faceName,
5012                      size = parent.font.size,
5013                      bold = parent.font.bold,
5014                      italic = parent.font.italic,
5015                      underline = parent.font.underline
5016                   };
5017                   //font = parent.font;
5018                   watch(parent) { font { } };
5019                }
5020                else
5021                   font = guiApp.currentSkin.SystemFont();
5022                AddResource(font);
5023
5024                firewatchers font;
5025             }
5026             */
5027
5028             captionFont = guiApp.currentSkin ? guiApp.currentSkin.CaptionFont() : null;
5029             AddResource(captionFont);
5030
5031             if(OnLoadGraphics())
5032             {
5033                int x,y,w,h;
5034
5035                display.Unlock();
5036
5037                //SetScrollLineStep(sbStep.x, sbStep.y);
5038                
5039                if(this != guiApp.desktop)
5040                {
5041                   if(resetAnchors)
5042                   {
5043                      normalAnchor = anchor;
5044                      normalSizeAnchor = sizeAnchor;
5045                   }
5046
5047                   // Break the anchors for moveable/resizable windows
5048                   /*
5049                   if(style.fixed && style.isDocument)
5050                   {
5051                      ComputeAnchors(ax, ay, aw, ah, &x, &y, &w, &h);
5052                      ax = x;
5053                      ay = y;
5054                      aw = w;
5055                      ah = h;
5056                      anchored = false;
5057                   }
5058                   */
5059                   switch(state)
5060                   {
5061                      case maximized:
5062                      
5063                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5064                         stateSizeAnchor = SizeAnchor {};
5065                         break;
5066                      
5067                      case minimized:
5068                      {
5069                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5070
5071                         stateAnchor = 
5072                            Anchor 
5073                            {
5074                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
5075                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
5076                            };
5077                         
5078                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5079                         break;
5080                      }
5081                      case normal:
5082                         stateAnchor = normalAnchor;
5083                         stateSizeAnchor = normalSizeAnchor;
5084                         break;
5085                   }
5086                   position = Point { };
5087                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5088
5089                }
5090                else
5091                {
5092                   x = scrolledPos.x;
5093                   y = scrolledPos.y;
5094                   w = size.w;
5095                   h = size.h;
5096                }
5097
5098                if(Position(x, y, w, h, true, false, true, true, true, true))
5099                {
5100                   if((this != guiApp.desktop || guiApp.fullScreenMode) && rootWindow == this)
5101                   {
5102                      if(!style.hidden)
5103                         guiApp.interfaceDriver.SetRootWindowState(this, normal, true);
5104                   }
5105
5106                   Update(null);
5107
5108                   result = true;
5109                }
5110             }
5111             else
5112             {
5113                result = false;
5114                display.Unlock();
5115             }
5116          }
5117       }
5118       else
5119       {
5120          success = result = true;
5121       }
5122
5123       if(!creation && result)
5124       {
5125          // Load menu bar first because sys buttons are on it...
5126          if(menuBar)
5127          {
5128             if(!menuBar.LoadGraphics(false, resetAnchors))
5129             {
5130                result = false;
5131                success = false;
5132             }
5133          }
5134          for(child = children.first; child; child = child.next)
5135          {
5136             if(child.created && child != menuBar && !child.LoadGraphics(false, resetAnchors))
5137             {
5138                result = false;
5139                success = false;
5140             }
5141          }
5142          if(!creation)
5143             CreateSystemChildren();
5144
5145          OnApplyGraphics();
5146       }
5147       if(this == guiApp.desktop && !guiApp.fullScreenMode)
5148       {
5149          if(activeChild)
5150             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
5151       }
5152       /*
5153       TODO:
5154       if(!success)
5155          //guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, caption);
5156          guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, class.name);
5157       */
5158
5159       // Do this here to avoid problems on Windows
5160       if(stateBackup == maximized)
5161          property::state = maximized;
5162       return result;
5163    }
5164
5165    void UnloadGraphics(bool destroyWindows)
5166    {
5167       Window child;
5168
5169       // Free children's graphics
5170       for(child = children.first; child; child = child.next)
5171          child.UnloadGraphics(destroyWindows);
5172
5173       if(display)
5174          display.Lock(false);
5175
5176       // Free cursors
5177       if(guiApp.fullScreenMode && this == guiApp.desktop)
5178       {
5179          Cursor cursor;
5180          SystemCursor c;
5181
5182          for(c=0; c<SystemCursor::enumSize; c++)
5183             if(guiApp.systemCursors[c].bitmap)
5184                delete guiApp.systemCursors[c].bitmap;
5185
5186          for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5187             delete cursor.bitmap;
5188
5189          guiApp.cursorBackground.Free();
5190       }
5191
5192       if(display && display.displaySystem)
5193       {
5194          ResPtr ptr;
5195
5196          for(ptr = resources.first; ptr; ptr = ptr.next)
5197          {
5198             if(ptr.loaded)
5199             {
5200                display.displaySystem.UnloadResource(ptr.resource, ptr.loaded);
5201                ptr.loaded = null;
5202             }
5203          }
5204
5205          // Free window graphics
5206          OnUnloadGraphics();
5207
5208          // Free skin graphics
5209          if(rootWindow == this)
5210          {
5211             DisplaySystem displaySystem = display.displaySystem;
5212             if(is3D)
5213             {
5214                display.driverData = null;
5215                display.displaySystem = null;
5216             }
5217             display.Unlock();
5218             delete display;
5219             if(displaySystem && !displaySystem.numDisplays && !is3D)
5220                delete displaySystem;
5221          }
5222          else
5223          {
5224             display.Unlock();
5225             display = null;
5226          }
5227       }
5228
5229       if(guiApp.acquiredWindow && this == guiApp.acquiredWindow.rootWindow)
5230          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, false);
5231
5232       if(this == guiApp.desktop || parent == guiApp.desktop)
5233       {
5234          if((guiApp.fullScreenMode || this != guiApp.desktop) && rootWindow == this && windowHandle && destroyWindows)
5235             guiApp.interfaceDriver.DestroyRootWindow(this);
5236       }
5237    }
5238
5239    // --- Window Hiding ---
5240
5241    void SetVisibility(bool state)
5242    {
5243       bool visible = (style.hidden || !created) ? false : state;
5244       if(visible != this.visible)
5245       {
5246          Window child;
5247
5248          this.visible = visible;
5249          for(child = children.first; child; child = child.next)
5250             child.SetVisibility(visible);
5251          Update(null);
5252          ConsequentialMouseMove(false);
5253          if(parent && !nonClient) parent.OnChildVisibilityToggled(this, visible);
5254       }
5255    }
5256
5257    // --- Windows and graphics initialization / termination ---
5258
5259    bool DisplayModeChanged(void)
5260    {
5261       bool result = false;
5262       if(!guiApp.fullScreenMode && !guiApp.modeSwitching/* && guiApp.desktop.active*/)
5263       {
5264          guiApp.modeSwitching = true;
5265          UnloadGraphics(false);
5266          if(SetupDisplay())
5267             if(LoadGraphics(false, false))
5268                result = true;
5269          guiApp.modeSwitching = false;
5270       }
5271       return result;
5272    }
5273
5274    // --- Window updates system ---
5275
5276    void UpdateDirty(Box updateBox)
5277    {
5278       if(!manageDisplay) { OnRedraw(null);return; }
5279       if(visible)
5280       {
5281          if(display && (!guiApp.fullScreenMode || guiApp.desktop.active) && !guiApp.modeSwitching)
5282          {
5283             display.Lock(true);
5284             if(display.flags.flipping)
5285             {
5286                Update(null);
5287                rootWindow.UpdateDisplay();
5288             }
5289             else
5290                UpdateBackDisplay(updateBox);
5291
5292             if(guiApp.fullScreenMode)
5293             {
5294                guiApp.cursorUpdate = true;
5295                guiApp.PreserveAndDrawCursor();
5296             }
5297             if(guiApp.fullScreenMode)
5298                guiApp.RestoreCursorBackground();
5299             display.Unlock();
5300          }
5301       }
5302    }
5303
5304    // This function is strictly called as a result of system window activation
5305    bool ExternalActivate(bool active, bool activateRoot, Window window, Window swap)
5306    {
5307       bool result = true;
5308       Window interimMaster = null;
5309       Window interimWindow = guiApp.interimWindow;
5310       if(interimWindow && interimWindow.master)
5311          interimMaster = interimWindow.master.rootWindow;
5312
5313       if(active && state == minimized) // && (!window.nativeDecorations || window.rootWindow != window)
5314          // SetState(normal, false, 0);
5315          SetState(lastState, false, 0);
5316
5317       if(interimMaster && swap == interimMaster && interimMaster.IsSlaveOf(window))
5318          return false;
5319
5320       incref this;
5321       /* WTH is this doing here?
5322       while(swap && swap.activeChild)
5323       {
5324          swap = swap.activeChild;         
5325       }
5326       */
5327       // TESTING THIS BEFORE...
5328       if(interimWindow && this == interimMaster)
5329       {
5330          if(active)
5331          {
5332             // Window interimSwap = this;
5333             Window menuBar = this.menuBar;
5334             if(menuBar && interimWindow.master == menuBar)
5335             {
5336                /*
5337                while(interimSwap && interimSwap.activeChild)
5338                   interimSwap = interimSwap.activeChild;
5339
5340                result = interimWindow.ActivateEx(false, false, false, activateRoot, null,
5341                (menuBar && interimWindow.master == menuBar) ? menuBar : interimSwap);
5342                */
5343                result = /*interimWindow.*/ActivateEx(false, false, false, activateRoot, null, menuBar);
5344                //result = ActivateEx(true, true, false, activateRoot, window, null);
5345             }
5346          }
5347       }
5348       else
5349          // Testing & FindModal() here: broke reactivating when a modal dialog is up (didn't root activate dialog)
5350          result = ActivateEx(active, active, false, activateRoot /*&& FindModal()*/, window, swap);
5351
5352       if(interimWindow == this && interimMaster && !active)
5353       {
5354          while(interimMaster && interimMaster.interim && interimMaster.master)
5355          {
5356             // printf("Going up one master %s\n", interimMaster._class.name);
5357             interimMaster = interimMaster.master.rootWindow;
5358          }
5359          // printf("Unactivating interim master %s (%x)\n", interimMaster._class.name, interimMaster);
5360          interimMaster.ActivateEx(active, active, false, activateRoot, window, swap);
5361       }
5362       delete this;
5363       return result;
5364    }
5365
5366    bool DestroyEx(int64 returnCode)
5367    {
5368       OldLink slave;
5369       Timer timer, nextTimer;
5370       Window child;
5371       OldLink prevOrder = null;
5372       Window client = null;
5373
5374       if(parent) stopwatching(parent, font); 
5375
5376       // if(window.modalSlave) return false;
5377       if(destroyed || !created)
5378       {
5379          if(master)
5380          {
5381             /*
5382             if(destroyed)
5383             {
5384                OldLink slave = master.slaves.FindLink(this);
5385                master.slaves.Delete(slave);
5386             }
5387             */
5388             // TOFIX IMMEDIATELY: COMMENTED THIS OUT... causes problem second time creating file dialog
5389             //master = null;
5390          }
5391          return true;
5392       }
5393
5394       this.returnCode = (DialogResult)returnCode;
5395
5396       AcquireInput(false);
5397
5398       destroyed = true;
5399       if(hotKey)
5400       {
5401          master.hotKeys.Delete(hotKey);
5402          hotKey = null;
5403       }
5404
5405       if(guiApp.prevWindow == this)
5406       {
5407          guiApp.prevWindow = null;
5408          OnMouseLeave(0);
5409       }
5410       if(guiApp.caretOwner == this) 
5411       {
5412          guiApp.interfaceDriver.SetCaret(0,0,0);
5413          UpdateCaret(false, true);
5414          guiApp.caretEnabled = false;
5415       }
5416
5417       /*
5418       if(cycle)
5419          parent.childrenCycle.Remove(cycle);
5420       */
5421       if(order)
5422       {
5423          OldLink tmpPrev = order.prev;
5424          if(tmpPrev && !(((Window)tmpPrev.data).style.hidden) && !(((Window)tmpPrev.data).destroyed) && (((Window)tmpPrev.data).created))
5425             prevOrder = tmpPrev;
5426          for(;;)
5427          {
5428             client = tmpPrev ? tmpPrev.data : null;
5429             if(client == this) { client = null; break; }
5430             if(client && (client.style.hidden || client.destroyed || !client.created))
5431                tmpPrev = client.order.prev;
5432             else
5433             {
5434                if(client)
5435                   prevOrder = tmpPrev;
5436                break;
5437             }
5438          }
5439
5440          // If this window can be an active client, make sure the next window we activate can also be one
5441          if(!style.nonClient && style.isActiveClient)
5442          {
5443             tmpPrev = prevOrder;
5444             for(;;)
5445             {
5446                client = tmpPrev ? tmpPrev.data : null;
5447                if(client == this) { client = null; break; }
5448                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
5449                   tmpPrev = client.order.prev;
5450                else 
5451                {
5452                   if(client)
5453                      prevOrder = tmpPrev;
5454                   break;
5455                }
5456             }
5457             if(client && client.style.hidden) client = null;
5458          }
5459          // parent.childrenOrder.Remove(order);
5460       }
5461
5462       if(parent && style.isActiveClient && visible)
5463       {
5464          if(state == minimized) parent.numIcons--;
5465          parent.numPositions--;
5466       }
5467
5468       // TESTING THIS HERE!
5469       created = false;
5470       visible = false;
5471
5472       // If no display, don't bother deactivating stuff (causes unneeded problems when trying
5473       // to create a window inside a rootwindow that's being destroyed)
5474       // DISABLED THIS BECAUSE OF CREATING WINDOW IN DESKTOP IN WINDOWED MODE
5475
5476       if(master && !master.destroyed /*&&
5477          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5478       {
5479          if(master.defaultControl == this)
5480             master.defaultControl = null;
5481       }
5482       if(parent)
5483          parent.OnChildAddedOrRemoved(this, true);
5484       if(parent && !parent.destroyed /*&&
5485          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5486       {
5487          if((parent.activeChild == this /*|| parent.activeClient == this */|| guiApp.interimWindow == this))
5488          {
5489             if(order && prevOrder && prevOrder.data != this && active)
5490             {
5491                //((Window)prevOrder.data).ActivateEx(true, false, false, false /*true*/, null);
5492
5493                ((Window)prevOrder.data).ActivateEx(true, false, false, (rootWindow == this) ? true : false, null, null);
5494                if(parent.activeClient == this)
5495                {
5496                   parent.activeClient = null;
5497                   parent.UpdateActiveDocument(null);
5498                }
5499             }
5500             else 
5501             {
5502                if(guiApp.interimWindow == this)
5503                {
5504                   bool goOn = true;
5505                   PropagateActive(false, null, &goOn, true);
5506                }
5507                else
5508                {
5509                   //if(window.parent.activeChild == window)
5510                      parent.activeChild = null;
5511                   if(!style.nonClient /*&& style.isActiveClient*/)
5512                   {
5513                      Window previous = parent.activeClient;
5514                      if(style.isActiveClient)
5515                         parent.activeClient = null;
5516                      parent.UpdateActiveDocument(previous);
5517                   }
5518                }
5519             }
5520          }
5521          else if(parent.activeClient == this)
5522          {
5523             parent.activeClient = client;
5524             parent.UpdateActiveDocument(this);
5525
5526          }
5527       }
5528       if(guiApp.interimWindow == this)
5529       {
5530          guiApp.interimWindow = null;
5531          if(guiApp.caretOwner)
5532          {
5533             Window desktop = guiApp.desktop;
5534             if(desktop.activeChild && desktop.activeChild.menuBar && !desktop.activeChild.menuBar.focus)
5535                guiApp.caretOwner.UpdateCaret(false, false);
5536          }
5537       }
5538
5539       active = false;
5540       if(_isModal && master && master.modalSlave == this)
5541          master.modalSlave = null;
5542
5543       if(parent)
5544       {
5545          if(!guiApp.caretOwner && parent.caretSize)
5546          {
5547             guiApp.caretOwner = parent;
5548             parent.UpdateCaret(false, false);
5549             parent.Update(null);
5550          }
5551
5552          // Why was this commented out?
5553          GetRidOfVirtualArea();
5554       }
5555       /*
5556       delete cycle;
5557       delete order;
5558       */
5559       dirtyArea.Free(null);
5560       dirtyBack.Free(null);
5561       scrollExtent.Free(null);
5562
5563       /* ATTEMPTING TO MOVE THAT ABOVE
5564       created = false;
5565       visible = false;
5566       */
5567
5568       /*
5569       OnDestroy();
5570       {
5571          //Window next;
5572          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5573          for(;(child = window.children.first);)
5574          {
5575             for(; child && (child.destroyed || !child.created); child = child.next);
5576             if(child)
5577                child.DestroyEx(0);
5578             else
5579                break;
5580          }
5581       }
5582       */
5583
5584       UnloadGraphics(true);
5585
5586       if(previousActive)
5587          delete previousActive;
5588
5589       menuBar = null;
5590       // statusBar = null;
5591       sbv = sbh = null;
5592
5593       if(master && !master.destroyed)
5594       {
5595          //master.NotifyDestroyed(this, this.returnCode);
5596          NotifyDestroyed(master, this, this.returnCode);
5597       }
5598
5599       for(timer = guiApp.windowTimers.first; timer; timer = nextTimer)
5600       {
5601          nextTimer = timer.next;
5602          if(timer.window == this)
5603          {
5604             // WHY WERE WE SETTING THIS TO NULL? NO MORE WINDOW WHEN RECREATING...
5605             // timer.window = null;
5606             timer.Stop();
5607             //delete timer;
5608          }
5609       }
5610
5611       if(this == guiApp.windowMoving)
5612          StopMoving();
5613
5614       if(guiApp.windowCaptured == this)
5615          ReleaseCapture();
5616          //guiApp.windowCaptured = null;
5617
5618       if(rootWindow != this && rootWindow)
5619          rootWindow.ConsequentialMouseMove(false);
5620
5621       rootWindow = null;
5622
5623       OnDestroy();
5624
5625       {
5626          //Window next;
5627          //for(child = children.first; next = child ? child.next : null, child; child = next)
5628          for(;(child = children.first); )
5629          {
5630             for(; child && (child.destroyed || !child.created); child = child.next);
5631             if(child)
5632                child.DestroyEx(0);
5633             else
5634                break;
5635          }
5636       }
5637
5638       // master = null;
5639
5640       /* // MOVED THIS UP...
5641       {
5642          //Window next;
5643          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5644          for(;(child = window.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
5655       while((slave = slaves.first))
5656       {
5657          for(; slave && (((Window)slave.data).destroyed || !((Window)slave.data).created); slave = slave.next);
5658          if(slave)
5659             ((Window)slave.data).DestroyEx(0);
5660          else
5661             break;
5662       }
5663
5664       if(guiApp.caretOwner == this)
5665          guiApp.caretOwner = null;
5666
5667       sysButtons[0] = null;
5668       sysButtons[1] = null;
5669       sysButtons[2] = null;
5670       activeChild = null;
5671
5672       if(rootWindow != this)
5673       {
5674          Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
5675          if(style.nonClient)
5676          {
5677             box.left   -= parent.clientStart.x;
5678             box.top    -= parent.clientStart.y;
5679             box.right  -= parent.clientStart.x;
5680             box.bottom -= parent.clientStart.y;
5681          }
5682          if(parent) parent.Update(box);
5683       }
5684       /*
5685       if(master)
5686       {
5687          OldLink slave = master.slaves.FindVoid(this);
5688          master.slaves.Delete(slave);
5689          master = null;
5690       }
5691
5692       if(parent)
5693       {
5694          parent.children.Remove(this);
5695          parent = null;
5696       }
5697       */
5698
5699       //autoCreate = false;
5700       //created = false;
5701
5702       // SHOULD THIS BE HERE? FIXED CRASH WITH GOTO DIALOG
5703       if(((subclass(Window))_class).pureVTbl)
5704       {
5705          if(_vTbl == _class._vTbl)
5706          {
5707             _vTbl = ((subclass(Window))_class).pureVTbl;
5708          }
5709          else
5710          {
5711             int m;
5712             for(m = 0; m < _class.vTblSize; m++)
5713             {
5714                if(_vTbl[m] == _class._vTbl[m])
5715                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5716             }
5717          }
5718       }
5719
5720       delete this;
5721       return true;
5722    }
5723
5724    void SetStateEx(WindowState newState, bool activate)
5725    {
5726       int x,y,w,h;
5727       WindowState prevState = state;
5728
5729       state = newState;
5730
5731       if(prevState != newState)
5732          lastState = prevState;
5733
5734       if(rootWindow != this || !nativeDecorations || !windowHandle)
5735       {
5736          if(style.isActiveClient && !style.hidden && prevState == minimized)
5737             parent.numIcons--;
5738
5739          // This block used to be at the end of the function... moved it for flicker problem in X
5740          // ------------------------------------------------------
5741          switch(state)
5742          {
5743             case normal:
5744                stateAnchor = normalAnchor;
5745                stateSizeAnchor = normalSizeAnchor;
5746                break;
5747             case maximized:
5748                stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5749                stateSizeAnchor = SizeAnchor {};
5750                break;
5751             case minimized:
5752             {
5753                int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5754                Window child;
5755                int size = 256;
5756                byte * idBuffer = new0 byte[size];
5757                int c;
5758                for(child = parent.children.first; child; child = child.next)
5759                {
5760                   if(child != this && child.state == minimized)
5761                   {
5762                      if(child.iconID > size - 2)
5763                      {
5764                         idBuffer = renew0 idBuffer byte[size*2];
5765                         memset(idBuffer + size, 0, size);
5766                         size *= 2;
5767                      }
5768                      idBuffer[child.iconID] = (byte)bool::true;
5769                   }
5770                }
5771                for(c = 0; c<size; c++)
5772                   if(!idBuffer[c])
5773                      break;
5774                iconID = c;
5775                delete idBuffer;
5776                if(style.isActiveClient && !style.hidden)
5777                   parent.numIcons++;
5778
5779                stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
5780                stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5781                break;
5782             }
5783          }
5784          // TOCHECK: Why was this here?
5785          //position.x = (tx > 0) ? tx & 0xFFFFF : tx;
5786          //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
5787          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5788
5789          Position(x, y, w, h, true, true, true, true, false, true);
5790
5791          if(!style.inactive && !style.interim && this == parent.activeClient)
5792             parent.UpdateActiveDocument(null);
5793       }
5794
5795       CreateSystemChildren();
5796       // ------------------------------------------------------
5797    }
5798
5799    int GetPositionID(Window forChild)
5800    {
5801       Window child;
5802       int size = 256;
5803       byte * idBuffer = new0 byte[size];
5804       int c;
5805
5806       for(child = children.first; child; child = child.next)
5807       {
5808          if(child.style.isActiveClient && !child.style.hidden && child != forChild)
5809          {
5810             if(child.positionID > size - 2)
5811             {
5812                idBuffer = renew0 idBuffer byte[size*2];
5813                memset(idBuffer + size, 0, size);
5814                size *= 2;
5815             }
5816             idBuffer[child.positionID] = (byte)bool::true;
5817          }
5818       }
5819       for(c = 0; c<size; c++)
5820          if(!idBuffer[c])
5821             break;
5822       delete idBuffer;
5823       return c;
5824    }
5825
5826    // --- Window related graphics ---
5827
5828    void SetPalette(ColorAlpha * newPalette, bool colorMatch)
5829    {
5830       palette = newPalette;
5831       if(rootWindow.display)
5832          rootWindow.display.SetPalette(palette, colorMatch);
5833    }
5834
5835    public bool AcquireInput(bool acquired)
5836    {
5837       bool result = true;
5838       if(acquiredInput != acquired)
5839       {
5840          if(active || (!visible && creationActivation == activate))
5841             result = AcquireInputEx(acquired);
5842          /*if(!result)
5843          {
5844             Print("");
5845          }*/
5846          acquiredInput = acquired ? result : !result;
5847       }
5848       return result;
5849    }
5850
5851    void ListChildren(ListBox listBox)
5852    {
5853       Window child;
5854       char caption[2048];
5855       for(child = children.first; child; child = child.next)
5856       {
5857          if(child.cycle && !child.style.nonClient && child.style.isActiveClient && child.visible)
5858          {
5859             DataRow row = listBox.AddRow();
5860             row.tag = (int64)child;
5861             child.FigureCaption(caption);
5862             row.SetData(null, caption);
5863          }
5864       }
5865    }
5866
5867    void UpdateVisual(Box extent)
5868    {
5869       if(guiApp.driver != null)
5870       {
5871          if(guiApp.fullScreenMode && guiApp.desktop.display)
5872          {
5873             guiApp.desktop.mutex.Wait();
5874             guiApp.desktop.display.Lock(true);
5875          
5876             Update(extent);
5877             if(guiApp.desktop.active)
5878             {
5879                if(guiApp.desktop.dirty || guiApp.cursorUpdate)
5880                {
5881                   if(guiApp.desktop.display.flags.flipping)
5882                      guiApp.desktop.Update(null);
5883                   guiApp.desktop.UpdateDisplay();
5884                   guiApp.cursorUpdate = true;
5885                }
5886                if(guiApp.cursorUpdate || guiApp.desktop.dirty)
5887                {
5888                   guiApp.PreserveAndDrawCursor();
5889                   // guiApp.desktop.display.ShowScreen();
5890                   guiApp.cursorUpdate = false;
5891                   guiApp.desktop.dirty = false;
5892                   guiApp.RestoreCursorBackground();
5893                }
5894             }
5895          
5896             guiApp.desktop.display.Unlock();
5897             guiApp.desktop.mutex.Release();
5898          }
5899          else
5900          {
5901             Window rootWindow = this.rootWindow;
5902             rootWindow.mutex.Wait();
5903             display.Lock(true);
5904          
5905             Update(extent);
5906             if(guiApp.waiting)
5907                guiApp.SignalEvent();
5908             else
5909             {
5910                guiApp.waitMutex.Wait();
5911                guiApp.interfaceDriver.Lock(rootWindow);
5912                if(!rootWindow.style.hidden && rootWindow.dirty)
5913                {
5914                   if(rootWindow.display)
5915                   {
5916                      rootWindow.UpdateDisplay();
5917                      //rootWindow.display.ShowScreen(null);
5918                   }
5919                   rootWindow.dirty = false;
5920                }
5921                guiApp.interfaceDriver.Unlock(rootWindow);
5922                guiApp.waitMutex.Release();
5923             }
5924             display.Unlock();
5925             rootWindow.mutex.Release();
5926          }
5927       }
5928    }
5929
5930    void UnlockDisplay(void)
5931    {
5932       guiApp.interfaceDriver.Unlock(rootWindow);
5933    }
5934
5935    void LockDisplay(void)
5936    {
5937       guiApp.interfaceDriver.Lock(rootWindow);
5938    }
5939
5940    Surface GetSurface(Box box)
5941    {
5942       return Redraw((box == null) ? this.box : box);
5943    }
5944
5945    void SetMousePosition(int x, int y)
5946    {
5947       guiApp.interfaceDriver.SetMousePosition(x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y);
5948    }
5949
5950    /*
5951    void IntegrationActivate(bool active)
5952    {
5953       if(!guiApp.modeSwitching && !guiApp.fullScreenMode)
5954       {
5955          isForegroundWindow = true;
5956          ActivateEx(active, active, false, false, null, null);
5957          isForegroundWindow = false;
5958       }  
5959    }
5960    */
5961
5962    Window QueryCapture(void)
5963    {
5964       return guiApp.windowCaptured;
5965    }
5966
5967    int GetDocumentID(void)
5968    {
5969       Window child;
5970       int size = 256;
5971       byte * idBuffer = new0 byte[size];
5972       int c;
5973
5974       for(child = children.first; child; child = child.next)
5975       {
5976          // TO CHECK: Do we want a documentID when we already have a file name?
5977          if(child.style.isDocument && !child.fileName)
5978          {
5979             if(child.documentID-1 > size - 2)
5980             {
5981                idBuffer = renew0 idBuffer byte[size*2];
5982                memset(idBuffer + size, 0, size);
5983                size *= 2;
5984             }
5985             idBuffer[child.documentID-1] = 1;
5986          }
5987       }
5988       for(c = 0; c<size; c++)
5989          if(!idBuffer[c])
5990             break;
5991       numDocuments++;
5992       delete idBuffer;
5993       return c + 1;
5994    }
5995
5996    void SetInitSize(Size size)
5997    {
5998       int x, y, w, h;
5999       sizeAnchor.size = size;
6000       normalSizeAnchor = sizeAnchor;
6001
6002       // Break the anchors for moveable/resizable windows
6003       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6004       {
6005          stateAnchor = normalAnchor;
6006          stateSizeAnchor = normalSizeAnchor;
6007
6008          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6009          Position(x,y, w, h, true, true, true, true, false, true);
6010       }
6011    }
6012
6013    void MenuMoveOrSize(bool resize, bool setCursorPosition)
6014    {
6015       if(this != guiApp.desktop && state != maximized && (resize ? (state != minimized && style.sizable) : (style.fixed || moveable)))
6016       {
6017          guiApp.windowIsResizing = resize;
6018          guiApp.windowMoving = this;
6019          guiApp.windowMovingStart = guiApp.movingLast = absPosition;
6020          if(guiApp.windowIsResizing)
6021          {
6022             guiApp.windowMovingStart.x += size.w - 1;
6023             guiApp.windowMovingStart.y += size.h - 1;
6024          }
6025          guiApp.windowMovingBefore = scrolledPos;
6026          guiApp.windowResizingBefore = size;
6027          guiApp.windowMoving.UpdateDecorations();
6028          if(guiApp.windowIsResizing) 
6029             guiApp.resizeEndX = guiApp.resizeEndY = true;
6030
6031          if(setCursorPosition)
6032             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
6033          else
6034          {
6035             int x, y;
6036             guiApp.interfaceDriver.GetMousePosition(&x, &y);
6037             guiApp.windowMovingStart.x += x - absPosition.x;
6038             guiApp.windowMovingStart.y += y - absPosition.y;
6039          } 
6040
6041          if(guiApp.windowMoving)
6042          {
6043             if(guiApp.windowMoving.style.nonClient)
6044                guiApp.windowMoving.parent.SetMouseRangeToWindow();
6045             else
6046                guiApp.windowMoving.parent.SetMouseRangeToClient();
6047          }
6048
6049          Capture();
6050
6051          if(this == rootWindow)
6052             guiApp.interfaceDriver.StartMoving(rootWindow, guiApp.windowMovingStart.x, guiApp.windowMovingStart.y, true);
6053       }
6054    }
6055
6056 public:
6057    // normal Methods
6058    bool Create()
6059    {
6060       bool result = false;
6061
6062       if(created)
6063          result = true;
6064       else if(guiApp && guiApp.driver != null)
6065       {
6066          void * systemParent = null;
6067          OldLink slaveHolder;
6068          Window last;
6069          bool visible = !style.hidden;
6070
6071          if(style.embedded) 
6072          {
6073             systemParent = parent;
6074             parent = guiApp.desktop;
6075          }
6076          last = parent ? parent.children.last : null;
6077
6078          if((parent && parent != guiApp.desktop && !parent.created) ||
6079             (master && master != guiApp.desktop && !master.created))
6080             return false;
6081
6082          if(parent)
6083             stopwatching(parent, font);
6084
6085          if(!parent)
6086             property::parent = guiApp.desktop;
6087          if(!master) master = parent;
6088
6089          if(_isModal && master.modalSlave)
6090             property::master = master.modalSlave;
6091             //return false;
6092
6093          if(parent)
6094             parent.children.Remove(this);
6095          if(master)
6096          {
6097             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
6098                if(slaveHolder.data == this)
6099                {
6100                   master.slaves.Delete(slaveHolder);
6101                   break;
6102                }
6103          }
6104
6105          if(parent == guiApp.desktop && !mutex)
6106             mutex = Mutex {};
6107
6108          if(style.isDocument)
6109          {
6110             if(parent)
6111                parent.numDocuments--;
6112             documentID = parent.GetDocumentID();
6113          }
6114
6115          if(!style.stayOnTop)
6116             for(; last && last.style.stayOnTop; last = last.prev);
6117
6118          parent.children.Insert((last == this) ? null : last, this);
6119          //parent.children.Add(this);
6120
6121          if(!dispDriver)
6122             dispDriver = parent.dispDriver;
6123          destroyed = false;
6124          if(_isModal)
6125             master.modalSlave = this;
6126
6127          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
6128
6129          incref this;
6130          incref this;
6131
6132          master.slaves.Add(slaveHolder = OldLink { data = this });
6133          if(slaveHolder)
6134          {
6135             if(setHotKey)
6136             {
6137                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
6138             }
6139             if(style.isDefault && !master.defaultControl)
6140                master.defaultControl = this;
6141
6142             stateAnchor = normalAnchor = anchor;
6143             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
6144
6145             // TOCHECK: Why is this here?
6146             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
6147             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
6148
6149             this.visible = false;
6150             style.hidden = true;
6151     
6152             //created = true;
6153             // autoCreate = true;
6154             wasCreated = true;
6155             if(SetupDisplay())
6156             {
6157                created = true;
6158                if(OnCreate())
6159                {
6160                   /*
6161                   if(parent == guiApp.desktop)
6162                      Log("LoadGraphics %s\n", caption);
6163                   */
6164                   if(LoadGraphics(true, false))
6165                   {
6166                      if(!setFont)
6167                      {
6168                         watch(parent)
6169                         {
6170                            font
6171                            {
6172                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
6173                               firewatchers font;
6174                               Update(null);
6175                            }
6176                         };
6177                      }
6178
6179                      if(style.hasMenuBar /*&& menu*/)
6180                      {
6181                         menuBar = 
6182                            PopupMenu
6183                            {
6184                               this,
6185                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
6186                               interim = false, inactive = true, nonClient = true, size.h = 24
6187                            };
6188                         menuBar.Create();
6189                      }
6190
6191                      if(statusBar)
6192                         statusBar.Create();
6193                      
6194                      // Create the system buttons
6195                      CreateSystemChildren();
6196
6197                      UpdateActiveDocument(null);
6198
6199                      if(style.isDocument)
6200                      {
6201                         if(menu)
6202                         {
6203                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6204                            if(item) item.disabled = !modifiedDocument && fileName;
6205                         }
6206                      }
6207
6208                      /*
6209                      if(parent == guiApp.desktop)
6210                         Log("Preemptive SetState %s\n", caption);
6211                      */
6212
6213                      // Preemptive Set State to ensure proper anchoring
6214                      SetStateEx(state, false);
6215                      /*
6216                      style.hidden = true;
6217                      visible = false;
6218                      */
6219
6220                      {
6221                         Window child, next;
6222                         for(child = children.first; child; child = next)
6223                         {
6224                            next = child.next;
6225                            if(!child.created && (child.autoCreate || child.wasCreated))
6226                               child.Create();
6227                         }
6228                      }
6229
6230                      {
6231                         OldLink link, next;
6232                         for(link = slaves.first; link; link = next)
6233                         {
6234                            Window slave = link.data;
6235                            next = link.next;
6236                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6237                            {
6238                               if(slave.Create())
6239                                  // Things might have happened that invalidated 'next'...
6240                                  // Start over the search for slaves to create.
6241                                  // (Added this to fix crash with Stacker & Toolbar)
6242                                  next = slaves.first;
6243                            }
6244                         }
6245                      }
6246
6247                      if(OnPostCreate())
6248                         OnApplyGraphics();
6249
6250                      /*
6251                      if(parent == guiApp.desktop)
6252                         Log("Real SetState %s\n", caption);
6253                      */
6254
6255                      if(isActiveClient && visible)
6256                      {
6257                         parent.numPositions--;
6258                         if(state == minimized) parent.numIcons--;
6259                      }
6260
6261                      parent.OnChildAddedOrRemoved(this, false);
6262
6263                      // Real set state & activate for proper display & activation
6264                      property::visible = visible;
6265                      //  SetState(state & 0x00000003, true, 0);
6266                      guiApp.interfaceDriver.SetIcon(this, icon);
6267
6268                      if(visible)
6269                      {
6270                         UpdateCaption();
6271                         /*if(rootWindow == this)
6272                            guiApp.interfaceDriver.ActivateRootWindow(this);
6273                         else*/
6274                         if(creationActivation == activate)
6275                            ActivateEx(true, false, true, true, null, null);
6276                         else if(creationActivation == flash)
6277                            Flash();
6278                      }
6279
6280                      if(!destroyed)
6281                         rootWindow.ConsequentialMouseMove(false);
6282
6283                      result = true;
6284                   }
6285                }
6286             }
6287          }
6288          /*
6289          if(!result)
6290          {
6291             Destroy(0);
6292             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6293          }
6294          */
6295
6296          if(!result)
6297          {
6298             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6299             created = false;
6300             //style.hidden = true; // !visible;
6301             style.hidden = !visible;
6302             if(master.modalSlave == this)
6303                master.modalSlave = null;
6304          }
6305          delete this;
6306       }
6307       return result;
6308    }
6309
6310    void WriteCaption(Surface surface, int x, int y)
6311    {
6312       if(caption)
6313          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6314    }
6315
6316    void Update(Box region)
6317    {
6318       if(this)
6319       {
6320          Window rootWindow;
6321
6322          rootWindow = this.rootWindow;
6323
6324          // rootWindow.mutex.Wait();
6325          if(!destroyed && visible && display)
6326          {
6327             Window child;
6328             Box realBox;
6329             
6330             // Testing this to avoid repetitve full update to take time...
6331             if(dirtyArea.count == 1)
6332             {
6333                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6334                if(item.box.left <= box.left &&
6335                   item.box.top <= box.top &&
6336                   item.box.right >= box.right &&
6337                   item.box.bottom >= box.bottom)
6338                {
6339                   rootWindow.dirty = true;
6340                   return;
6341                }
6342             }
6343
6344             if(display.flags.flipping && !rootWindow.dirty)
6345             {
6346                if(this == rootWindow)
6347                   region = null;
6348                else
6349                {
6350                   rootWindow.Update(null);
6351                   return;
6352                }
6353             }
6354             
6355             rootWindow.dirty = true;
6356
6357             if(region != null)
6358             {
6359                realBox = region;
6360                realBox.left += clientStart.x;
6361                realBox.top += clientStart.y;
6362                realBox.right += clientStart.x;
6363                realBox.bottom += clientStart.y;
6364                realBox.Clip(box);
6365             }
6366             else
6367                realBox = box;
6368
6369             if(realBox.right >= realBox.left && 
6370                realBox.bottom >= realBox.top)
6371             {
6372                // if(!rootWindow.fullRender)
6373                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6374
6375                for(child = children.first; child; child = child.next)
6376                {
6377                   if(!child.is3D)
6378                   {
6379                      Box box = realBox;
6380                      box.left -= child.absPosition.x - absPosition.x;
6381                      box.top -= child.absPosition.y - absPosition.y;
6382                      box.right -= child.absPosition.x - absPosition.x;
6383                      box.bottom -= child.absPosition.y - absPosition.y;
6384                      if(box.right >= child.box.left && box.left <= child.box.right &&
6385                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6386                      {
6387                         box.left -= child.clientStart.x;
6388                         box.top -= child.clientStart.y;
6389                         box.right -= child.clientStart.x;
6390                         box.bottom -= child.clientStart.y;
6391                         child.Update(box);
6392                      }
6393                   }
6394                }
6395
6396                realBox.left += absPosition.x - rootWindow.absPosition.x;
6397                realBox.top += absPosition.y - rootWindow.absPosition.y;
6398                realBox.right += absPosition.x - rootWindow.absPosition.x;
6399                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6400                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6401             }
6402          }
6403          else if(this == guiApp.desktop)
6404          {
6405             Window window;
6406             for(window = children.first; window; window = window.next)
6407             {
6408                if(!window.is3D)
6409                {
6410                   if(region != null)
6411                   {
6412                      Box childBox = region;
6413
6414                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6415                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6416                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6417                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6418        
6419                      window.Update(childBox);
6420                   }
6421                   else
6422                      window.Update(null);
6423                }
6424             }
6425          }
6426
6427          // rootWindow.mutex.Release();
6428       }
6429    }
6430
6431    bool Capture(void)
6432    {
6433       bool result = true;
6434       if(guiApp.windowCaptured != this)
6435       {
6436          if(guiApp.windowCaptured)
6437             result = false;
6438          else
6439          {
6440             //Logf("Captured %s (%s)\n", caption, class.name);
6441             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6442             guiApp.windowCaptured = this;
6443          }
6444       }
6445       return result;
6446    }
6447
6448    bool Destroy(int64 code)
6449    {
6450       //if(created)
6451       if(this)
6452       {
6453          if(!destroyed && !CloseConfirmation(false)) return false;
6454          incref this;
6455          if(DestroyEx(code))
6456          {
6457             // TOCHECK: Should autoCreate be set to false here?
6458             autoCreate = false;
6459             wasCreated = false;
6460             delete this;
6461             return true;
6462          }
6463          delete this;
6464       }
6465       return false;
6466    }
6467
6468    void Move(int x, int y, int w, int h)
6469    {
6470       normalAnchor = Anchor { left = x, top = y };
6471       normalSizeAnchor = SizeAnchor { size = { w, h } };
6472
6473       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6474       {
6475          if(destroyed) return;
6476
6477          stateAnchor = normalAnchor;
6478          stateSizeAnchor = normalSizeAnchor;
6479
6480          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6481          Position(x,y, w, h, true, true, true, true, false, true);
6482       }
6483    }
6484
6485    DialogResult Modal(void)
6486    {
6487       isModal = true;
6488       if(Create())
6489          return DoModal();
6490
6491       // FIXES MEMORY LEAK IF Create() FAILED
6492       incref this;
6493       delete this;
6494       return 0;
6495    }
6496
6497    void SetScrollArea(int width, int height, bool snapToStep)
6498    {
6499       bool resize = false;
6500       if(snapToStep)
6501       {
6502          int stepX = sbStep.x, stepY = sbStep.y;
6503          // Needed to make snapped down position match the skin's check of client area 
6504          // against realvirtual
6505          if(guiApp.textMode)
6506          {
6507             SNAPDOWN(stepX, textCellW);
6508             SNAPDOWN(stepY, textCellH);
6509             stepX = Max(stepX, textCellW);
6510             stepY = Max(stepY, textCellH);
6511          }
6512          if(scrollFlags.snapX)
6513             SNAPUP(width, stepX);
6514          if(scrollFlags.snapY)
6515             SNAPUP(height, stepY);
6516       }
6517
6518       reqScrollArea.w = width;
6519       reqScrollArea.h = height;
6520       noAutoScrollArea = (width > 0 || height > 0);
6521
6522       UpdateScrollBars(true, true);
6523    }
6524
6525    void SetScrollPosition(int x, int y)
6526    {
6527       if(sbh)
6528          sbh.Action(setPosition, x, 0);
6529       else
6530       {
6531          int range;
6532          int seen = clientSize.w, total = reqScrollArea.w;
6533          seen = Max(1,seen);
6534          if(scrollFlags.snapX)
6535             SNAPDOWN(seen, sbStep.x);
6536
6537          if(!total) total = seen;
6538          range = total - seen + 1;
6539          range = Max(range, 1);
6540          if(x < 0) x = 0;
6541          if(x >= range) x = range - 1;
6542
6543          if(scrollFlags.snapX)
6544             SNAPUP(x, sbStep.x);
6545
6546          if(scroll.x != x)
6547             OnHScroll(setPosition, x, 0);
6548
6549          if(guiApp.textMode)
6550          {
6551             SNAPDOWN(x, textCellW);
6552          }
6553          scroll.x = x;
6554       }
6555
6556       if(sbv)
6557          sbv.Action(setPosition, y, 0);
6558       else
6559       {
6560          int range;
6561          int seen = clientSize.h, total = reqScrollArea.h;
6562          seen = Max(1,seen);
6563
6564          if(scrollFlags.snapY)
6565             SNAPDOWN(seen, sbStep.y);
6566
6567          if(!total) total = seen;
6568          range = total - seen + 1;
6569          range = Max(range, 1);
6570          if(y < 0) y = 0;
6571          if(y >= range) y = range - 1;
6572
6573          if(scrollFlags.snapY)
6574             SNAPUP(y, sbStep.y);
6575
6576          if(scroll.y != y)
6577             OnVScroll(setPosition, y, 0);
6578          if(guiApp.textMode)
6579          {
6580             SNAPDOWN(y, textCellH);
6581          }
6582          scroll.y = y;
6583       }
6584       if(!sbh || !sbv)
6585          UpdateCaret(false, false);
6586    }
6587
6588    void SetScrollLineStep(int stepX, int stepY)
6589    {
6590       sbStep.x = stepX;
6591       sbStep.y = stepY;
6592       if(guiApp.textMode)
6593       {
6594          SNAPDOWN(stepX, textCellW);
6595          SNAPDOWN(stepY, textCellH);
6596          stepX = Max(stepX, textCellW);
6597          stepY = Max(stepY, textCellH);
6598       }
6599       if(sbh)
6600          sbh.lineStep = stepX;
6601       if(sbv)
6602          sbv.lineStep = stepY;
6603    }
6604
6605    void SetState(WindowState newState, bool activate, Modifiers mods)
6606    {
6607       if(created)
6608       {
6609          if(state == newState || OnStateChange(newState, mods))
6610          {
6611             WindowState prevState = state;
6612
6613             StopMoving();
6614
6615             // This used to be at the end of the brackets... moved for X, testing...
6616             // This has the effect of activating the window through the system...
6617             if(rootWindow == this)
6618                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6619       
6620             SetStateEx(newState, activate);
6621
6622             if(rootWindow == this && !rootWindow.nativeDecorations)
6623             {
6624                int x = position.x, y = position.y;
6625                /*if(style.interim)
6626                {
6627                   x -= guiApp.desktop.absPosition.x;
6628                   y -= guiApp.desktop.absPosition.y;
6629                }*/
6630                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6631             }
6632
6633             //state = newState;
6634             //state = prevState;
6635
6636             if(state != maximized && style.hasMaximize)
6637             {
6638                Window child;
6639                for(child = parent.children.first; child; child = child.next)
6640                {
6641                   if(child != this && child.state == maximized)
6642                      child.SetStateEx(normal, false);
6643                }
6644             }
6645
6646             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6647                parent.UpdateScrollBars(true, true);
6648
6649             /*
6650             // Do we really need this stuff here? 
6651             // Shouldn't the Activate stuff take care of it?              
6652             if(parent.rootWindow == parent && style)
6653             {
6654                char caption[2048];
6655                parent.FigureCaption(caption);
6656                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6657                parent.UpdateDecorations();
6658             }         
6659             */
6660
6661             rootWindow.ConsequentialMouseMove(false);
6662          }
6663       }
6664       else
6665          state = newState;
6666    }
6667
6668    BitmapResource GetIcon(SkinBitmap iconID)
6669    {
6670       return guiApp.currentSkin.GetBitmap(iconID);
6671    }
6672
6673    void SetMouseRange(Box range)
6674    {
6675       if(range || guiApp.fullScreenMode)
6676       {
6677          Box clip;
6678          if(range != null)
6679          {
6680             clip.left   = range.left + absPosition.x + clientStart.x;
6681             clip.top    = range.top + absPosition.y + clientStart.y;
6682             clip.right  = range.right + absPosition.x + clientStart.x;
6683             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6684          }
6685          else
6686          {
6687             clip.left   = guiApp.desktop.box.left;
6688             clip.top    = guiApp.desktop.box.top;
6689             clip.right  = guiApp.desktop.box.right;
6690             clip.bottom = guiApp.desktop.box.bottom;
6691          }
6692          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6693       }
6694       else
6695          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6696    }
6697
6698    void SetMouseRangeToClient(void)
6699    {
6700       if(guiApp.fullScreenMode || this != guiApp.desktop)
6701       {
6702          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6703          box.Clip(clientArea);
6704          SetMouseRange(box);
6705       }
6706       else
6707          SetMouseRange(null);
6708    }
6709
6710    void SetMouseRangeToWindow(void)
6711    {
6712       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6713       if(this == guiApp.desktop)
6714          SetMouseRangeToClient();
6715       else
6716          SetMouseRange(box);
6717    }
6718
6719    // x, y: Desktop Coordinates
6720    void ShowSysMenu(int x, int y)
6721    {
6722       Menu menu { };
6723       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6724       MenuItem
6725       {
6726          menu, $"Restore", r, NotifySelect = MenuWindowRestore, 
6727          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6728       };
6729       MenuItem
6730       {
6731          menu, $"Move", m, NotifySelect = MenuWindowMove, 
6732          disabled = !style.fixed || state == maximized
6733       };
6734       MenuItem
6735       {
6736          menu, $"Size", s, NotifySelect = MenuWindowSize, 
6737          disabled = !style.sizable || state != normal
6738       };
6739       MenuItem
6740       {
6741          menu, $"Minimize", n, NotifySelect = MenuWindowMinimize, 
6742          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6743       };
6744       MenuItem
6745       {
6746          menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize, 
6747          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6748       };
6749       MenuItem
6750       {
6751          menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop, 
6752          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6753       };
6754       MenuDivider { menu };
6755       MenuItem
6756       {
6757          menu, $"Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6758          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6759       };
6760       windowMenu.Create();
6761    }
6762
6763    void Activate(void)
6764    {
6765       ActivateEx(true, true, true, true, null, null);
6766    }
6767
6768    void MakeActive(void)
6769    {
6770       ActivateEx(true, false, true, false, null, null);
6771    }
6772
6773    void SoftActivate(void)
6774    {
6775       if(guiApp.desktop.active)
6776          Activate();
6777       else if(!active)
6778          Flash();
6779    }
6780
6781    void Deactivate(void)
6782    {
6783       ActivateEx(false, true, true, true, null, null);
6784    }
6785
6786    void Flash(void)
6787    {
6788       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6789    }
6790
6791    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6792    {
6793       bool result = false;
6794       if(activeChild && activeChild.cycle)
6795       {
6796          Window modalWindow, child = activeChild;
6797          if(!clientOnly /*&& parent.tabCycle*/)
6798          {
6799             Window next = child;
6800             while(true)
6801             {
6802                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6803                {
6804                   if(cycleParents)
6805                   {
6806                      if(parent && parent.CycleChildren(backward, false, true, true))
6807                         return true;
6808                      break;
6809                   }
6810                   else
6811                      return false;
6812                }
6813                if(backward)
6814                   next = next.cycle.prev.data;
6815                else
6816                   next = next.cycle.next.data;
6817                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6818                   break;
6819             }
6820          }
6821          /*
6822          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) && 
6823             parent.tabCycle && parent.CycleChildren(backward, false, false))
6824             return true;
6825          */
6826
6827          if(tabCycleOnly && !tabCycle) return false;
6828
6829          while(child)
6830          {
6831             while(true)
6832             {
6833                if(backward)
6834                   child = child.cycle.prev.data;
6835                else
6836                   child = child.cycle.next.data;
6837                if(child == child.parent.activeChild)
6838                   return result;
6839                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6840                   break;
6841             }
6842             modalWindow = child.FindModal();
6843             if(!modalWindow)
6844             {
6845                // Scroll the window to include the active control
6846                if(sbh && !child.style.dontScrollHorz)
6847                {
6848                   if(child.scrolledPos.x < 0)
6849                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6850                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6851                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6852                }
6853                if(sbv && !child.style.dontScrollVert)
6854                {
6855                   if(child.scrolledPos.y < 0)
6856                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6857                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6858                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6859                }
6860             }
6861             result = true;
6862             child = modalWindow ? modalWindow : child;
6863             child.ActivateEx(true, true, true, true, null, null);
6864             if(child.tabCycle && child.childrenCycle.first)
6865                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6866             else
6867                break;
6868          }
6869       }
6870       else
6871          return false;
6872
6873       ConsequentialMouseMove(false);
6874       return result;
6875    }
6876
6877    void AddResource(Resource resource)
6878    {
6879       if(resource)
6880       {
6881          ResPtr ptr { resource = resource };
6882          resources.Add(ptr);
6883          incref resource;
6884
6885          // Load Graphics here if window is created already
6886          if(/*created && */display)
6887          {
6888             display.Lock(false);
6889             ptr.loaded = display.displaySystem.LoadResource(resource);
6890             display.Unlock();
6891          }
6892          /*
6893          // Temporary hack to load font right away for listbox in dropbox ...
6894          else if(master && master.display)
6895          {
6896             master.display.Lock(false);
6897             master.display.displaySystem.LoadResource(resource);
6898             master.display.Unlock();
6899          }
6900          */
6901       }
6902    }
6903
6904    void RemoveResource(Resource resource)
6905    {
6906       if(resource)
6907       {
6908          ResPtr ptr;
6909          for(ptr = resources.first; ptr; ptr = ptr.next)
6910          {
6911             if(ptr.resource == resource)
6912                break;
6913          }
6914
6915          if(ptr)
6916          {
6917             // Unload Graphics here if window is created already
6918             if(/*created && */display)
6919             {
6920                if(ptr.loaded)
6921                {
6922                   display.Lock(false);
6923                   display.displaySystem.UnloadResource(resource, ptr.loaded);
6924                   display.Unlock();
6925                   ptr.loaded = null;
6926                }
6927             }
6928             delete resource;
6929             resources.Delete(ptr);
6930          }
6931       }
6932    }
6933
6934    void SetCaret(int x, int y, int size)
6935    {
6936       if(!destroyed)
6937       {
6938          caretPos.x = x;
6939          caretPos.y = y;
6940          caretSize = size;
6941          if(active && !style.interim)
6942          {
6943             if(visible || !guiApp.caretOwner)
6944                guiApp.caretOwner = size ? this : null;
6945             if(size)
6946                UpdateCaret(false, false);
6947             else
6948             {
6949                guiApp.interfaceDriver.SetCaret(0,0,0);
6950                UpdateCaret(false, true);
6951                guiApp.caretEnabled = false;
6952             }
6953          }
6954          else if(style.inactive && active)
6955          {
6956             guiApp.interfaceDriver.SetCaret(0,0,0);
6957             UpdateCaret(false, true);
6958             guiApp.caretEnabled = false;
6959          }
6960       }
6961    }
6962
6963    void Scroll(int x, int y)
6964    {
6965       bool opaque = !style.drawBehind || background.a;
6966       if(opaque && display && display.flags.scrolling)
6967       {
6968          Box box = clientArea;
6969          box.left += clientStart.x;
6970          box.top += clientStart.y;
6971          box.right += clientStart.x;
6972          box.bottom += clientStart.y;
6973
6974          //scrollExtent.Free(null);
6975          scrollExtent.AddBox(box);
6976          scrolledArea.x += x;
6977          scrolledArea.y += y;
6978
6979          //scrollExtent.Free();
6980          //scrollExtent.AddBox(clientArea);
6981          //scrollExtent.Offset(clientStart.x, clientStart.y);
6982          //scrolledArea.x = x;
6983          //scrolledArea.y = y;
6984       }
6985       else
6986          Update(clientArea);
6987
6988       if(rootWindow)
6989          rootWindow.dirty = true;
6990    }
6991
6992    void ReleaseCapture()
6993    {
6994       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
6995       {
6996          Window oldCaptured = guiApp.windowCaptured;
6997          guiApp.windowCaptured = null;
6998          guiApp.prevWindow = null;
6999          incref oldCaptured;
7000
7001          //guiApp.Log("Released Capture\n");
7002
7003          guiApp.interfaceDriver.SetMouseCapture(null);
7004
7005          //oldCaptured.OnMouseCaptureLost();
7006
7007          if(oldCaptured)
7008             oldCaptured.ConsequentialMouseMove(false);
7009          delete oldCaptured;
7010       }
7011    }
7012
7013    private void _SetCaption(char * format, va_list args)
7014    {
7015       if(this)
7016       {
7017          delete caption;
7018          if(format)
7019          {
7020             char caption[MAX_F_STRING];
7021             vsnprintf(caption, sizeof(caption), format, args);
7022             caption[sizeof(caption)-1] = 0;
7023
7024             this.caption = CopyString(caption);
7025          }
7026          if(created)
7027             UpdateCaption();
7028
7029          firewatchers caption;
7030       }
7031    }
7032
7033    /*deprecated*/ void SetText(char * format, ...)
7034    {
7035       va_list args;
7036       va_start(args, format);
7037       _SetCaption(format, args);
7038       va_end(args);
7039    }
7040
7041    void SetCaption(char * format, ...)
7042    {
7043       va_list args;
7044       va_start(args, format);
7045       _SetCaption(format, args);
7046       va_end(args);
7047    }
7048
7049    bool Grab(Bitmap bitmap, Box box, bool decorations)
7050    {
7051       bool result = false;
7052       if(display || this == guiApp.desktop)
7053       {
7054          Box clip = {MININT, MININT, MAXINT, MAXINT};
7055
7056          if(box != null)
7057             clip = box;
7058
7059          if(!decorations)
7060             clip.Clip(clientArea);
7061          else
7062             clip.Clip(this.box);
7063
7064          if(rootWindow != this)
7065          {
7066             clip.left   += absPosition.y;
7067             clip.top    += absPosition.y;
7068             clip.right  += absPosition.x;
7069             clip.bottom += absPosition.y;
7070          }
7071
7072          clip.left += decorations ? 0 : clientStart.x;
7073          clip.top += decorations ? 0 : clientStart.y;
7074          clip.right += decorations ? 0 : clientStart.x;
7075          clip.bottom += decorations ? 0 : clientStart.y;
7076
7077          if(display && display.flags.flipping)
7078          {
7079             rootWindow.Update(null);
7080             rootWindow.UpdateDisplay();
7081          }
7082
7083          if(!display)
7084          {
7085             Window window { };
7086             window.Create();
7087             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
7088                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7089             delete window;
7090          }
7091          else
7092             result = display.Grab(bitmap, clip.left, clip.top, 
7093                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7094
7095          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7096          {
7097             if(!bitmap.Convert(null, pixelFormat888, null))
7098                result = false;
7099          }
7100       }
7101       return result;
7102    }
7103
7104    void GetMousePosition(int * x, int * y)
7105    {
7106       int mouseX = 0, mouseY = 0;
7107       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7108       {
7109          if(guiApp.driver)
7110             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7111          if(this != guiApp.desktop)
7112          {
7113             mouseX -= absPosition.x + clientStart.x;
7114             mouseY -= absPosition.y + clientStart.y;
7115          }
7116       }
7117       if(x) *x = mouseX;
7118       if(y) *y = mouseY;
7119    }
7120
7121    DialogResult DoModal()
7122    {
7123       DialogResult returnCode = 0;
7124       int terminated = terminateX;
7125       isModal = true;
7126       incref this;
7127       while(!destroyed && guiApp.driver != null)
7128       {
7129          if(terminateX != terminated)
7130          {
7131             terminated = terminateX;
7132             guiApp.desktop.Destroy(0);
7133             if(guiApp.desktop.created)
7134             {
7135                terminated = 0;
7136                //printf("Resetting terminate X to 0\n");
7137                terminateX = 0;
7138             }
7139             break;
7140          }
7141
7142          guiApp.UpdateDisplay();
7143          if(!guiApp.ProcessInput(false))
7144             guiApp.Wait();
7145       }
7146       returnCode = this.returnCode;
7147       delete this;
7148       return returnCode;
7149    }
7150
7151    void DoModalStart()
7152    {
7153       isModal = true;
7154       incref this;
7155    }
7156
7157    bool DoModalLoop()
7158    {
7159       return !destroyed && guiApp.driver != null && terminateX < 2;
7160    }
7161
7162    DialogResult DoModalEnd()
7163    {
7164       DialogResult returnCode = this.returnCode;
7165       delete this;
7166       return returnCode;
7167    }
7168
7169    // --- Window manipulation ---
7170    /*bool GetDisabled()
7171    {
7172       bool disabled = this.disabled;
7173       Window window;
7174       for(window = this; (window = window.master); )
7175       {
7176          if(window.disabled)
7177          {
7178             disabled = true;
7179             break;
7180          }
7181       }
7182       return disabled;
7183    }*/
7184
7185    // --- Mouse Manipulation ---
7186    void GetNCMousePosition(int * x, int * y)
7187    {
7188       GetMousePosition(x, y);
7189       if(x) *x += clientStart.x;
7190       if(y) *y += clientStart.y;
7191    }
7192
7193    // --- Carets manipulation ---
7194    void GetCaretPosition(Point caretPos)
7195    {
7196       caretPos = this.caretPos;
7197    }
7198
7199    int GetCaretSize(void)
7200    {
7201       return caretSize;
7202    }
7203
7204    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7205    {
7206       Destroy(button.id);
7207       return true;
7208    }
7209
7210    bool CloseConfirmation(bool parentClosing)
7211    {
7212       bool result = true;
7213       OldLink slave;
7214       Window child;
7215
7216       if(closing)
7217          return false;
7218       if(terminateX > 1)
7219          return true;
7220          
7221       closing = true;
7222
7223       if(!OnClose(parentClosing))
7224          result = false;
7225
7226       // If you want to skip this, simply set modifiedDocument to false in OnClose
7227       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7228       {
7229          DialogResult dialogRes;
7230          char message[1024];
7231          if(fileName)
7232             sprintf(message, $"Save changes to %s?", fileName);
7233          else
7234             sprintf(message, $"Save changes to Untitled %d?", documentID);
7235
7236          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7237
7238          if(dialogRes == yes)
7239          {
7240             // TOFIX: Precomp error if brackets are taken out
7241             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7242          }
7243          else if(dialogRes == cancel)
7244             result = false;
7245       }
7246
7247       if(result)
7248       {
7249          for(slave = slaves.first; slave; slave = slave.next)
7250          {
7251             Window w = slave.data;
7252             if((w.parent == this || !w.IsDescendantOf(this)) && !w.CloseConfirmation(true))
7253             {
7254                // ((Window)slave.data).CloseConfirmation(true);
7255                result = false;
7256                break;
7257             }
7258          }
7259       }
7260
7261       if(result)
7262       {
7263          for(child = children.first; child; child = child.next)
7264             if(child.master != this && !child.CloseConfirmation(true))
7265             {
7266                result = false;
7267                break;
7268             }
7269       }
7270       closing = false;
7271       return result;
7272    }
7273
7274    // Static methods... move them somewhere else?
7275    void ::RestoreCaret()
7276    {
7277       if(guiApp.caretOwner)
7278          guiApp.caretOwner.UpdateCaret(false, false);
7279    }
7280
7281    void ::FreeMouseRange()
7282    {
7283       guiApp.interfaceDriver.SetMouseRange(null, null);
7284    }
7285
7286    // Menu Methods
7287    bool MenuFileClose(MenuItem selection, Modifiers mods)
7288    {
7289       Window document = activeChild;
7290       if(document)
7291          document.Destroy(0);
7292       return true;
7293    }
7294
7295    bool MenuFileExit(MenuItem selection, Modifiers mods)
7296    {
7297       Destroy(0);
7298       return true;
7299    }
7300
7301    bool MenuFileSave(MenuItem selection, Modifiers mods)
7302    {
7303       if(fileName)
7304       {
7305          fileMonitor.fileName = null;
7306          saving = true;
7307
7308          if(OnSaveFile(fileName))
7309          {
7310             //if(OnFileModified != Window::OnFileModified)
7311             {
7312                saving = false;
7313                fileMonitor.fileName = fileName;
7314             }
7315             return true;
7316          }
7317          else
7318          {
7319             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7320             DialogResult answer = dialog.Modal();
7321             saving = false;
7322             if(answer != yes) return (bool)answer;
7323          }
7324       }
7325       return MenuFileSaveAs(selection, mods);
7326    }
7327
7328    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7329    {
7330       DialogResult result = (DialogResult)bool::true;
7331       FileDialog fileDialog = saveDialog;
7332
7333       if(!fileDialog)
7334          fileDialog = FileDialog {};
7335       if(fileDialog)
7336       {
7337          incref fileDialog;
7338          if(fileName)
7339             fileDialog.filePath = fileName;
7340          else
7341          {
7342             char filePath[MAX_FILENAME];
7343             sprintf(filePath, "Untitled %d", documentID);
7344             fileDialog.filePath = filePath;
7345          }
7346          fileMonitor.fileName = null;
7347
7348          fileDialog.type = save;
7349          fileDialog.text = $"Save As";
7350
7351          while(true)
7352          {
7353             fileDialog.master = master.parent ? master : this;
7354             if(fileDialog.Modal() == ok)
7355             {
7356                char * filePath = fileDialog.filePath;
7357                saving = true;
7358                if(OnSaveFile(filePath))
7359                {
7360                   saving = false;
7361                   property::fileName = filePath;
7362                   NotifySaved(master, this, filePath);
7363                   break;
7364                }
7365                else
7366                {
7367                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7368                   DialogResult answer = dialog.Modal();
7369                   saving = false;
7370                   if(answer != yes) 
7371                   {
7372                      result = answer;
7373                      break;
7374                   }
7375                }
7376             }
7377             else
7378             {
7379                result = cancel;
7380                break;
7381             }
7382          }
7383          //if(OnFileModified != Window::OnFileModified && fileName)
7384          {
7385             if(fileName)
7386                fileMonitor.fileName = fileName;
7387          }
7388          delete fileDialog;
7389       }
7390       return (bool)result; // Actually returning result from Yes/NoCancel message box
7391    }
7392
7393    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7394    {
7395       Window document = activeChild;
7396       Window next;
7397       for(document = children.first; document; document = next)
7398       {
7399          next = document.next;
7400          if(document.style.isDocument || document.fileName)
7401             document.MenuFileSave(selection, mods);
7402       }
7403       return true;
7404    }
7405
7406    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7407    {
7408       Window document;
7409
7410       for(document = children.first; document; document = document.next)
7411          //if(document.style.isDocument && document.state == minimized)
7412          if(document.style.isActiveClient && document.state == minimized)
7413             document.SetState(minimized, false, mods);
7414       return true;
7415    }
7416
7417    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7418    {
7419       Window document = activeChild;
7420       if(document)
7421       {
7422          Window firstDocument = null;
7423          Window child;
7424          OldLink cycle = document.cycle.prev;
7425          int id = 0;
7426          while(true)
7427          {
7428             child = cycle.data;
7429             if(child.style.isActiveClient && !child.style.hidden)
7430             {
7431                Window last;
7432
7433                firstDocument = child;
7434                if(child.state == minimized)
7435                   child.SetState(minimized, false, mods);
7436                else
7437                {
7438                   child.positionID = id++;
7439                   child.SetState(normal, false, mods);
7440                   child.anchor.left.type = cascade;
7441                   {
7442                      int x, y, w, h;
7443                      child.normalSizeAnchor = *&child.sizeAnchor;
7444                      child.normalAnchor = child.anchor;
7445
7446                      // Break the anchors for moveable/resizable windows
7447                      if(child.style.fixed)
7448                      {
7449                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7450
7451                         (*&child.normalAnchor).left = x;
7452                         (*&child.normalAnchor).top = y;
7453                         (*&child.normalAnchor).right.type = none;
7454                         (*&child.normalAnchor).bottom.type = none;
7455
7456                         child.normalSizeAnchor.isClientW = false;
7457                         child.normalSizeAnchor.isClientH = false;
7458                         child.normalSizeAnchor.size.w = w;
7459                         child.normalSizeAnchor.size.h = h;
7460                         child.anchored = false;
7461                      }
7462
7463                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7464                      {
7465                         child.stateAnchor = child.normalAnchor;
7466                         child.stateSizeAnchor = child.normalSizeAnchor;
7467
7468                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7469                         child.Position(x, y, w, h, true, true, true, true, false, false);
7470                      }
7471                   }
7472                }
7473
7474                last = children.last;
7475                if(!child.style.stayOnTop)
7476                   for(; last && last.style.stayOnTop; last = last.prev);
7477                children.Move(child, last);
7478                childrenOrder.Move(child.order, childrenOrder.last);
7479             }
7480             if(cycle == document.cycle) break;
7481             cycle = cycle.prev;
7482          }
7483          if(firstDocument)
7484             firstDocument.Activate();
7485       }
7486       return true;
7487    }
7488
7489    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7490    {
7491       if(style.hasClose)
7492          Destroy(0);
7493       return true;
7494    }
7495
7496    // Close all closes all active clients, not all documents
7497    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7498    {
7499       Window next, document;
7500
7501       for(document = children.first; document; document = next)
7502       {
7503          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7504          if(document.style.isActiveClient)
7505             if(!document.Destroy(0) && !document.style.hidden)
7506                return false;
7507       }
7508       return true;
7509    }
7510
7511    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7512    {
7513       if(style.hasMaximize && state != maximized)
7514          SetState(maximized, 0, 0);
7515       return true;
7516    }
7517
7518    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7519    {
7520       if(style.hasMinimize && state != minimized)
7521       {
7522          SetState(minimized, 0, 0);
7523          parent.CycleChildren(false, true, false, true);
7524       }
7525       return true;
7526    }
7527
7528    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7529    {
7530       MenuMoveOrSize(false, selection ? true : false);
7531       return true;
7532    }
7533
7534    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7535    {
7536       CycleChildren(false, true, false, true);
7537       return true;
7538    }
7539
7540    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7541    {
7542       CycleChildren(true, true, false, true);
7543       return true;
7544    }
7545
7546    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7547    {
7548       MenuMoveOrSize(true, true);
7549       return true;
7550    }
7551
7552    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7553    {
7554       if(state != normal)
7555          SetState(normal, 0, 0);
7556       return true;
7557    }
7558
7559    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7560    {
7561       Window document;
7562       int64 id = selection.id;
7563       OldLink cycle = activeClient.cycle;
7564       int c = 0;
7565       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7566       while(true)
7567       {
7568          Window sibling = cycle.data;
7569          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7570          {
7571             if(c == id)
7572                break;
7573             c++;
7574          }
7575          cycle = cycle.next;
7576       }
7577       document = cycle.data;
7578       document.Activate();
7579       
7580       //if(activeChild.state == maximized)
7581       //  document.SetState(maximized, false, mods);
7582       //else if(document.state == minimized)
7583       //   document.SetState(normal, false, mods);
7584       return true;
7585    }
7586
7587    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7588    {
7589       stayOnTop = !style.stayOnTop;
7590       return true;
7591    }
7592
7593    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7594    {
7595       Window document = activeChild;
7596       if(document)
7597       {
7598          Window firstDocument = null;
7599          OldLink cycle = document.cycle;
7600          int id = 0;
7601          while(true)
7602          {
7603             Window child = cycle.data;
7604             if(child.style.isActiveClient && !child.style.hidden)
7605             {
7606                if(!firstDocument) firstDocument = child;
7607                if(child.state == minimized)
7608                   child.SetState(minimized, false, mods);
7609                else
7610                {
7611                   child.positionID = id++;
7612                   child.SetState(normal, false, mods);
7613                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7614
7615                   child.anchor.left.type = hTiled;
7616                   {
7617                      int x, y, w, h;
7618                      child.normalSizeAnchor = *&child.sizeAnchor;
7619                      child.normalAnchor = child.anchor;
7620
7621                      // Break the anchors for moveable/resizable windows
7622                      if(child.style.fixed)
7623                      {
7624                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7625
7626                         (*&child.normalAnchor).left = x;
7627                         (*&child.normalAnchor).top = y;
7628                         (*&child.normalAnchor).right.type = none;
7629                         (*&child.normalAnchor).bottom.type = none;
7630                         child.normalSizeAnchor.isClientW = false;
7631                         child.normalSizeAnchor.isClientH = false;
7632                         child.normalSizeAnchor.size.w = w;
7633                         child.normalSizeAnchor.size.h = h;
7634                         child.anchored = false;
7635                      }
7636
7637                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7638                      {
7639                         child.stateAnchor = child.normalAnchor;
7640                         child.stateSizeAnchor = child.normalSizeAnchor;
7641
7642                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7643                         child.Position(x,y, w, h, true, true, true, true, false, true);
7644                      }
7645                   }
7646                }
7647             }
7648             if((cycle = cycle.next) == document.cycle) break;
7649          }
7650          if(firstDocument)
7651             firstDocument.Activate();
7652       }
7653       return true;
7654    }
7655
7656    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7657    {
7658       Window document = activeChild;
7659       if(document)
7660       {
7661          Window firstDocument = null;
7662          Window child;
7663          OldLink cycle = document.cycle;
7664          int id = 0;
7665          while(true)
7666          {
7667             child = cycle.data;
7668             //if(child.style.isDocument)
7669             if(child.style.isActiveClient && !child.style.hidden)
7670             {
7671                if(!firstDocument) firstDocument = child;
7672                if(child.state == minimized)
7673                   child.SetState(minimized, false, mods);
7674                else
7675                {
7676                   child.positionID = id++;
7677                   child.SetState(normal, false, mods);
7678                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7679
7680                   child.anchor.left.type = vTiled;
7681                   {
7682                      int x, y, w, h;
7683                      child.normalSizeAnchor = *&child.sizeAnchor;
7684                      child.normalAnchor = child.anchor;
7685
7686                      // Break the anchors for moveable/resizable windows
7687                      if(child.style.fixed)
7688                      {
7689                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7690
7691                         (*&child.normalAnchor).left = x;
7692                         (*&child.normalAnchor).top = y;
7693                         (*&child.normalAnchor).right.type = none;
7694                         (*&child.normalAnchor).bottom.type = none;
7695                         child.normalSizeAnchor.isClientW = false;
7696                         child.normalSizeAnchor.isClientH = false;
7697                         child.normalSizeAnchor.size.w = w;
7698                         child.normalSizeAnchor.size.h = h;
7699                         child.anchored = false;
7700                      }
7701
7702                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7703                      {
7704                         child.stateAnchor = child.normalAnchor;
7705                         child.stateSizeAnchor = child.normalSizeAnchor;
7706
7707                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7708                         child.Position(x,y, w, h, true, true, true, true, false, true);
7709                      }
7710                   }
7711                }
7712             }
7713             if((cycle = cycle.next) == document.cycle) break;
7714          }
7715          if(firstDocument)
7716             firstDocument.Activate();
7717       }
7718       return true;
7719    }
7720
7721    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7722    {
7723       WindowList dialog { master = this };
7724       Window document = (Window)dialog.Modal();
7725       if(document)
7726       {
7727          if(activeChild.state == maximized)
7728             document.SetState(maximized, false, mods);
7729          else if(document.state == minimized)
7730             document.SetState(normal, false, mods);
7731          document.Activate();
7732       }
7733       return true;
7734    }
7735
7736    // Virtual Methods
7737    virtual bool OnCreate(void);
7738    virtual void OnDestroy(void);
7739    virtual void OnDestroyed(void);
7740    virtual bool OnClose(bool parentClosing);
7741    virtual bool OnStateChange(WindowState state, Modifiers mods);
7742    virtual bool OnPostCreate(void);
7743    virtual bool OnMoving(int *x, int *y, int w, int h);
7744    virtual bool OnResizing(int *width, int *height);
7745    virtual void OnResize(int width, int height);
7746    virtual void OnPosition(int x, int y, int width, int height);
7747    virtual bool OnLoadGraphics(void);
7748    virtual void OnApplyGraphics(void);
7749    virtual void OnUnloadGraphics(void);
7750    virtual void OnRedraw(Surface surface);
7751    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7752    virtual void OnActivateClient(Window client, Window previous);
7753    virtual bool OnKeyDown(Key key, unichar ch);
7754    virtual bool OnKeyUp(Key key, unichar ch);
7755    virtual bool OnKeyHit(Key key, unichar ch);
7756    virtual bool OnSysKeyDown(Key key, unichar ch);
7757    virtual bool OnSysKeyUp(Key key, unichar ch);
7758    virtual bool OnSysKeyHit(Key key, unichar ch);
7759    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7760    virtual bool OnMouseLeave(Modifiers mods);
7761    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7762    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7763    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7764    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7765    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7766    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7767    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7768    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7769    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7770    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7771    virtual void OnMouseCaptureLost(void);
7772    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7773    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7774    virtual void OnDrawOverChildren(Surface surface);
7775    virtual bool OnFileModified(FileChange fileChange, char * param);
7776    virtual bool OnSaveFile(char * fileName);
7777
7778    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
7779    // Note: A 'client' would refer to isActiveClient, rather than
7780    // being confined to the 'client area' (nonClient == false)
7781    virtual void OnChildAddedOrRemoved(Window child, bool removed);
7782    virtual void OnChildVisibilityToggled(Window child, bool visible);
7783    virtual void OnChildResized(Window child, int x, int y, int w, int h);
7784
7785    // Skins Virtual Functions
7786    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7787    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7788    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7789    {
7790       *cw = *w;
7791       *ch = *h;      
7792    }
7793    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7794    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7795    virtual bool IsMouseMoving(int x, int y, int w, int h)
7796    {
7797       return false;
7798    }
7799    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
7800    {
7801       return false;
7802    }
7803    virtual void UpdateNonClient();
7804    virtual void SetBox(Box box);    // This isn't used anywhere at this time
7805    virtual bool IsInside(int x, int y)
7806    {
7807       return box.IsPointInside({x, y});
7808    }
7809    virtual bool IsOpaque()
7810    {
7811       return (!style.drawBehind || background.a == 255);
7812    }
7813
7814    // Notifications
7815    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7816    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7817    virtual void Window::NotifySaved(Window window, char * filePath);
7818
7819    // Public Methods
7820
7821    // Properties
7822    property Window parent
7823    {
7824       property_category $"Layout"
7825       set
7826       {
7827          if(value || guiApp.desktop)
7828          {
7829             Window last;
7830             Window oldParent = parent;
7831             Anchor anchor = this.anchor;
7832
7833             if(value && value.IsDescendantOf(this)) return;
7834             if(value && value == this)
7835                return;
7836             if(!value) value = guiApp.desktop;
7837
7838             if(value == oldParent) return;
7839
7840             if(!master || (master == this.parent && master == guiApp.desktop))
7841                property::master = value;
7842             
7843             if(parent)
7844             {
7845                parent.children.Remove(this);
7846
7847                parent.Update(
7848                {
7849                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7850                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7851                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7852                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7853                });
7854             }
7855
7856             last = value.children.last;
7857
7858             if(style.isDocument)
7859             {
7860                if(parent)
7861                   parent.numDocuments--;
7862                documentID = value.GetDocumentID();
7863             }
7864
7865             if(style.isActiveClient && !style.hidden)
7866             {
7867                if(parent && parent != guiApp.desktop && !(style.hidden))
7868                {
7869                   if(state == minimized) parent.numIcons--;
7870                   parent.numPositions--;
7871                }
7872             }
7873
7874             if(!style.stayOnTop)
7875                for(; last && last.style.stayOnTop; last = last.prev);
7876
7877             value.children.Insert(last, this);
7878
7879             // *** NEW HERE: ***
7880             if(cycle)
7881                parent.childrenCycle.Delete(cycle);
7882             if(order)
7883                parent.childrenOrder.Delete(order);
7884             cycle = null;
7885             order = null;
7886             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
7887             //           Should something else be done?
7888             if(parent && parent.activeChild == this)
7889                parent.activeChild = null;
7890             if(parent && parent.activeClient == this)
7891                parent.activeClient = null;
7892
7893             //if(created)
7894             {
7895                if(created)
7896                {
7897                   int x = position.x, y = position.y, w = size.w, h = size.h;
7898                   
7899                   int vpw, vph;
7900
7901                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7902                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7903                   
7904                   vpw = value.clientSize.w;
7905                   vph = value.clientSize.h;
7906                   if(style.nonClient)
7907                   {
7908                      vpw = value.size.w;
7909                      vph = value.size.h;
7910                   }
7911                   else if(style.fixed)
7912                   {
7913                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7914                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7915                   }
7916
7917                   anchor = this.anchor;
7918
7919                   if(anchor.left.type == offset)            anchor.left.distance = x;
7920                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7921                   if(anchor.top.type == offset)             anchor.top.distance = y;
7922                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7923                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7924                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7925                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7926                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7927                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7928                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7929
7930                   if(!anchor.left.type && !anchor.right.type)
7931                   {
7932                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7933                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7934                   }
7935                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7936                   if(!anchor.top.type && !anchor.bottom.type)
7937                   {
7938                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7939                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7940                   }
7941                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7942                }
7943                parent = value;
7944                parent.OnChildAddedOrRemoved(this, false);
7945
7946                // *** NEW HERE ***
7947                if(!style.inactive)
7948                {
7949                   if(!style.noCycle)
7950                      parent.childrenCycle.Insert(
7951                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
7952                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
7953                         null,
7954                         cycle = OldLink { data = this });
7955                   parent.childrenOrder.Insert(
7956                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
7957                      order = OldLink { data = this });
7958                }
7959
7960                if(!style.hidden && style.isActiveClient)
7961                {
7962                   positionID = parent.GetPositionID(this);
7963                   parent.numPositions++;
7964                   if(state == minimized) parent.numIcons--;
7965                }
7966
7967                // *** FONT INHERITANCE ***
7968                if(!setFont && oldParent) 
7969                   stopwatching(oldParent, font);
7970
7971                if(systemFont)
7972                {
7973                   RemoveResource(systemFont);
7974                   delete systemFont;
7975                }
7976                // TESTING WITH WATCHERS:
7977                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7978                // usedFont = setFont ? setFont : (systemFont);
7979
7980                if(!usedFont)
7981                {
7982                   if(guiApp.currentSkin)
7983                   {
7984                      systemFont = guiApp.currentSkin.SystemFont();
7985                      incref systemFont;
7986                   }
7987                   usedFont = systemFont;
7988                   AddResource(systemFont);
7989                }
7990
7991                if(!setFont)
7992                   watch(value)
7993                   {
7994                      font
7995                      {
7996                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7997                         firewatchers font;
7998                         Update(null);
7999                      }
8000                   };
8001                
8002                firewatchers font;
8003
8004
8005                if(value.rootWindow && value.rootWindow.display && rootWindow)
8006                {
8007                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
8008                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
8009                   
8010                   if(reloadGraphics)
8011                      UnloadGraphics(false);
8012                   SetupDisplay();
8013                   if(reloadGraphics)
8014                      LoadGraphics(false, false);
8015                      
8016                   /*
8017                   if(value.rootWindow != rootWindow)
8018                      DisplayModeChanged();
8019                   else
8020                   */
8021                }
8022                scrolledPos.x = MININT; // Prevent parent update
8023                {
8024                   bool anchored = this.anchored;
8025                   property::anchor = anchor;
8026                   this.anchored = anchored;
8027                }
8028                /*
8029                {
8030                   int x, y, w, h;
8031                   if(guiApp.currentSkin)
8032                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
8033
8034                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8035                   Position(x, y, w, h, true, true, true, true, false, true);
8036                }
8037                */
8038
8039             }
8040             // else parent = value;
8041             if(oldParent)
8042                oldParent.OnChildAddedOrRemoved(this, true);
8043          }
8044       }
8045       get { return parent; }
8046    };
8047
8048    property Window master
8049    {
8050       property_category $"Behavior"
8051       set
8052       {
8053          //if(this == value) return;
8054          if(value && value.IsSlaveOf(this)) return;
8055
8056          if(master != value)
8057          {
8058             if(master)
8059             {
8060                OldLink slaveHolder;
8061                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8062                   if(slaveHolder.data == this)
8063                   {
8064                      master.slaves.Delete(slaveHolder);
8065                      break;
8066                   }
8067             }
8068
8069             if(value)
8070             {
8071                value.slaves.Add(OldLink { data = this });
8072
8073                if(hotKey)
8074                {
8075                   if(master)
8076                      master.hotKeys.Remove(hotKey);
8077                   value.hotKeys.Add(hotKey);
8078                   hotKey = null;
8079                }
8080                if(master && master.defaultControl == this)
8081                   master.defaultControl = null;
8082
8083                if(style.isDefault && !value.defaultControl)
8084                   value.defaultControl = this;
8085             }
8086          }
8087          master = value;
8088       }
8089       get { return master ? master : parent; }
8090    };
8091
8092    property char * caption
8093    {
8094       property_category $"Appearance"
8095       watchable
8096       set
8097       {
8098          delete caption;
8099          if(value)
8100          {
8101             caption = new char[strlen(value)+1];
8102             if(caption)
8103                strcpy(caption, value);
8104          }
8105          if(created)
8106             UpdateCaption();
8107       }
8108       get { return caption; }
8109    };
8110
8111    property Key hotKey
8112    {
8113       property_category $"Behavior"
8114       set
8115       {
8116          setHotKey = value;
8117          if(created)
8118          {
8119             if(value)
8120             {
8121                if(!hotKey)
8122                   master.hotKeys.Add(hotKey = HotKeySlot { });
8123                if(hotKey)
8124                {
8125                   hotKey.key = value;
8126                   hotKey.window = this;
8127                }
8128             }
8129             else if(hotKey)
8130             {
8131                master.hotKeys.Delete(hotKey);
8132                hotKey = null;
8133             }
8134          }
8135       }
8136       get { return hotKey ? hotKey.key : 0; }
8137    };
8138
8139    property Color background
8140    {
8141       property_category $"Appearance"
8142       set
8143       {
8144          background.color = value;
8145          firewatchers;
8146          if(created)
8147          {
8148             Update(null);
8149             if(this == rootWindow)
8150                guiApp.interfaceDriver.SetRootWindowColor(this);
8151          }
8152       }
8153       get { return background.color; }
8154    };
8155
8156    property Percentage opacity
8157    {
8158       property_category $"Appearance"
8159       set
8160       {
8161          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8162          drawBehind = (background.a == 255) ? false : true;
8163       }
8164       get { return background.a / 255.0f; }
8165    };
8166
8167    property Color foreground
8168    {
8169       property_category $"Appearance"
8170       set
8171       {
8172          foreground = value;
8173          firewatchers;
8174          if(created)
8175             Update(null);
8176       }
8177       get { return foreground; }
8178    };
8179
8180    property BorderStyle borderStyle
8181    {
8182       property_category $"Appearance"
8183       set
8184       {
8185          if(!((BorderBits)value).fixed)
8186          {
8187             style.hasClose = false;
8188             style.hasMaximize = false;
8189             style.hasMinimize = false;
8190             nativeDecorations = false;
8191          }
8192          style.borderBits = value;
8193          if(created)
8194          {
8195             int x, y, w, h;
8196             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8197
8198             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8199             Position(x, y, w, h, true, true, true, true, false, true);
8200             CreateSystemChildren();
8201          }
8202       }
8203       get { return (BorderStyle)style.borderBits; } 
8204    };
8205
8206    property Size minClientSize
8207    {
8208       property_category $"Layout"
8209       set { minSize = value; }
8210       get { value = minSize; }
8211    };
8212
8213    property Size maxClientSize
8214    {
8215       property_category $"Layout"
8216       set { maxSize = value; }
8217       get { value = maxSize; }
8218    };
8219
8220    property bool hasMaximize
8221    {
8222       property_category $"Window Style"
8223       set
8224       {
8225          style.hasMaximize = value;
8226          if(value) { style.fixed = true; style.contour = true; }
8227          if(created)
8228          {
8229             int x, y, w, h;
8230             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8231
8232             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8233             Position(x, y, w, h, true, true, true, true, false, true);
8234
8235             CreateSystemChildren();
8236          }
8237       }
8238       get { return style.hasMaximize; }
8239    };
8240
8241    property bool hasMinimize
8242    {
8243       property_category $"Window Style"
8244       set
8245       {
8246          style.hasMinimize = value;
8247          if(value) { style.fixed = true; style.contour = true; }
8248          if(created)
8249          {
8250             int x, y, w, h;
8251             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8252
8253             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8254             Position(x, y, w, h, true, true, true, true, false, true);
8255
8256             CreateSystemChildren();
8257          }
8258       }
8259       get { return style.hasMinimize;  }
8260    };
8261
8262    property bool hasClose
8263    {
8264       property_category $"Window Style"
8265       set
8266       {
8267          style.hasClose = value;
8268          if(value) { style.fixed = true; style.contour = true; }
8269          if(created)
8270          {
8271             int x, y, w, h;
8272             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8273             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8274             Position(x, y, w, h, true, true, true, true, false, true);
8275             CreateSystemChildren();
8276          }
8277       }
8278       get { return style.hasClose; }
8279    };
8280    
8281    property bool nonClient
8282    {
8283       property_category $"Layout"
8284       set
8285       {
8286          style.nonClient = value;
8287          if(value)
8288             style.stayOnTop = true;
8289       }
8290       get { return style.nonClient; }
8291    };
8292
8293    property bool inactive
8294    {
8295       property_category $"Behavior"
8296       set
8297       {
8298          if(value) 
8299          {
8300             // *** NEW HERE: ***
8301             if(!style.inactive)
8302             {
8303                if(cycle)
8304                   parent.childrenCycle.Delete(cycle);
8305                if(order)
8306                   parent.childrenOrder.Delete(order);
8307                cycle = null;
8308                order = null;
8309             }
8310
8311             if(created)
8312             {
8313                active = false; // true;
8314                if(parent.activeChild == this)
8315                   parent.activeChild = null;
8316                if(parent.activeClient == this)
8317                   parent.activeClient = null;
8318             }
8319          }
8320          else
8321          {
8322             if(style.inactive)
8323             {
8324                if(!style.noCycle)
8325                {
8326                   parent.childrenCycle.Insert(
8327                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8328                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
8329                      null,
8330                      cycle = OldLink { data = this });
8331                }
8332                parent.childrenOrder.Insert(
8333                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8334                   order = OldLink { data = this });
8335             }
8336          }
8337          style.inactive = value;
8338       }
8339       get { return style.inactive; }
8340    };
8341
8342    property bool clickThrough
8343    {
8344       property_category $"Behavior"
8345       set { style.clickThrough = value; }
8346       get { return style.clickThrough; }
8347    };
8348
8349    property bool isRemote
8350    {
8351       property_category $"Behavior"
8352       set { style.isRemote = value; }
8353       get { return style.isRemote; }
8354    };
8355
8356    property bool noCycle
8357    {
8358       property_category $"Behavior"
8359       set { style.noCycle = value; }
8360       get { return style.noCycle; }
8361    };
8362
8363    property bool isModal
8364    {
8365       property_category $"Behavior"
8366       set { style.modal = value; }
8367       get { return style.modal; }
8368    };
8369
8370    property bool interim
8371    {
8372       property_category $"Behavior"
8373       set { style.interim = value; }
8374       get { return style.interim; }
8375    };
8376
8377    property bool tabCycle
8378    {
8379       property_category $"Behavior"
8380       set { style.tabCycle = value; }
8381       get { return style.tabCycle; }
8382    };
8383      
8384    property bool isDefault
8385    {
8386       property_category $"Behavior"
8387       set
8388       {
8389          if(master)
8390          {
8391             if(value)
8392             {
8393                Window sibling;
8394                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8395                   if(sibling != this && sibling.style.isDefault)
8396                      sibling.style.isDefault = false;*/
8397                if(master.defaultControl)
8398                   master.defaultControl.style.isDefault = false;
8399                master.defaultControl = this;
8400             }
8401             else if(master.defaultControl == this)
8402                master.defaultControl = null;
8403
8404             // Update(null);
8405          }
8406          style.isDefault = value;
8407          if(created)
8408             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8409       }
8410       get { return style.isDefault; }
8411    };
8412
8413    property bool drawBehind
8414    {
8415       property_category $"Window Style"
8416       set { style.drawBehind = value; }
8417       get { return style.drawBehind; }
8418    };
8419
8420    property bool hasMenuBar
8421    {
8422       property_category $"Window Style"
8423       set
8424       {
8425          if(value) 
8426          {
8427             if(!menu)
8428             {
8429                menu = Menu { };
8430                incref menu;
8431             }
8432             if(created && !menuBar)
8433             {
8434                menuBar =
8435                   PopupMenu 
8436                   {
8437                      this, menu = menu,
8438                      isMenuBar = true,
8439                      anchor = Anchor { top = 23, left = 1, right = 1 },
8440                      size.h = 24,
8441                      inactive = true, nonClient = true                            
8442                   };
8443                menuBar.Create();
8444             }
8445          }
8446          else if(created && menuBar)
8447          {
8448             menuBar.Destroy(0);
8449             menuBar = null;
8450          }
8451          style.hasMenuBar = value;
8452       }
8453       get { return style.hasMenuBar; }
8454    };
8455
8456    property bool hasStatusBar
8457    {
8458       property_category $"Window Style"
8459       set
8460       {
8461          if(value)
8462          {
8463             if(!statusBar)
8464             {
8465                statusBar = StatusBar { this };
8466                incref statusBar;
8467                if(created)
8468                   statusBar.Create();
8469             }
8470          }
8471          else if(statusBar)
8472             delete statusBar;
8473          style.hasStatusBar = value;
8474       }
8475       get { return style.hasStatusBar; }
8476    };
8477    property bool stayOnTop
8478    {
8479       property_category $"Window Style"
8480       set
8481       {
8482          if(value)
8483          {
8484             if(created && !style.stayOnTop)
8485             {
8486                if(rootWindow == this)
8487                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8488                else if(parent.children.last != this)
8489                {
8490                   parent.children.Move(this, parent.children.last);
8491                   Update(null);
8492                }
8493             }
8494             style.stayOnTop = true;
8495          }
8496          else
8497          {
8498             if(created && style.stayOnTop)
8499             {
8500                if(rootWindow == this)
8501                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8502                else
8503                {
8504                   Window last;
8505                   if(order)
8506                   {
8507                      OldLink order;
8508                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
8509                          order && ((Window)order.data).style.stayOnTop;
8510                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8511                       last = order ? order.data : null;
8512                   }
8513                   else
8514                   {
8515                      for(last = parent.children.last; 
8516                          last && last.style.stayOnTop;
8517                          last = last.prev);
8518                   }
8519
8520                   parent.children.Move(this, last);
8521                   Update(null);
8522                }
8523             }
8524             style.stayOnTop = false;
8525          }
8526       }
8527       get { return style.stayOnTop; }
8528    };
8529
8530    property Menu menu
8531    {
8532       property_category $"Window Style"
8533       set
8534       {
8535          delete menu;
8536          if(value)
8537          {
8538             menu = value;
8539             incref menu;
8540          }
8541
8542          if(menuBar && !value)
8543          {
8544             menuBar.Destroy(0);
8545             menuBar = null;
8546          }
8547          if(created)
8548          {
8549             if(!menuBar && style.hasMenuBar && value)
8550             {
8551                menuBar = PopupMenu
8552                          { 
8553                             this, menu = value, isMenuBar = true, 
8554                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
8555                             inactive = true, nonClient = true
8556                          };
8557                 menuBar.Create();
8558             }
8559             UpdateActiveDocument(null);
8560          }
8561       }
8562       get { return menu; }
8563    };
8564
8565    property FontResource font
8566    {
8567       property_category $"Appearance"
8568       watchable
8569       isset { return setFont ? true : false; }
8570       set
8571       {
8572          if(this)
8573          {
8574             if(value && !setFont) { stopwatching(parent, font); }
8575             else if(!value && setFont)
8576             {
8577                watch(parent)
8578                {
8579                   font
8580                   {
8581                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8582                      firewatchers font;
8583                      Update(null);
8584                   }
8585                };
8586             }
8587
8588             if(setFont)
8589             {
8590                RemoveResource(setFont);
8591                delete setFont;
8592             }
8593             if(systemFont)
8594             {
8595                RemoveResource(systemFont);
8596                delete systemFont;
8597             }
8598             setFont = value;
8599             if(setFont)
8600             {
8601                incref setFont;
8602                AddResource(setFont);
8603             }
8604
8605             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8606             if(!usedFont)
8607             {
8608                systemFont = guiApp.currentSkin.SystemFont();
8609                incref systemFont;
8610                usedFont = systemFont;
8611                AddResource(systemFont);
8612             }
8613
8614             firewatchers;
8615
8616             Update(null);
8617          }
8618       }
8619       get { return usedFont; }
8620    };
8621
8622    property SizeAnchor sizeAnchor
8623    {
8624       property_category $"Layout"
8625       isset
8626       {
8627          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8628                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8629             sizeAnchor.isClientW != sizeAnchor.isClientH;
8630       }
8631       set
8632       {
8633          int x, y, w, h;
8634          sizeAnchor = value;
8635
8636          normalSizeAnchor = sizeAnchor;
8637
8638          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8639          {
8640             stateAnchor = normalAnchor;
8641             stateSizeAnchor = normalSizeAnchor;
8642
8643             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8644             Position(x,y, w, h, true, true, true, true, false, true);
8645          }
8646       }
8647       get
8648       {
8649          value =
8650          {
8651             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8652             sizeAnchor.isClientW,
8653             sizeAnchor.isClientH
8654          };
8655       }
8656    };
8657
8658    property Size size
8659    {
8660       property_category $"Layout"
8661       isset
8662       {
8663          Anchor thisAnchor = anchor;
8664          SizeAnchor thisSizeAnchor = sizeAnchor;
8665          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8666          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8667          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8668          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8669                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8670             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8671       }
8672       set
8673       {
8674          int x, y, w, h;
8675
8676          sizeAnchor.isClientW = false;
8677          sizeAnchor.isClientH = false;
8678          sizeAnchor.size = value;
8679
8680          normalSizeAnchor = sizeAnchor;
8681
8682          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8683          {
8684             stateAnchor = normalAnchor;
8685             stateSizeAnchor = normalSizeAnchor;
8686
8687             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8688             Position(x, y, w, h, true, true, true, true, false, true);
8689             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8690          }
8691       }
8692       get { value = size; }
8693    };
8694
8695    property Size clientSize
8696    {
8697       property_category $"Layout"
8698       isset
8699       {
8700          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8701                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8702             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8703       }
8704       set
8705       {
8706          int x, y, w, h;
8707          sizeAnchor.isClientW = true;
8708          sizeAnchor.isClientH = true;
8709          sizeAnchor.size = value;
8710
8711          normalSizeAnchor = sizeAnchor;
8712
8713          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8714          {
8715             stateAnchor = normalAnchor;
8716             stateSizeAnchor = normalSizeAnchor;
8717
8718             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8719             Position(x,y, w, h, true, true, true, true, false, true);
8720          }
8721       }
8722       get { value = clientSize; }
8723    };
8724
8725    property Size initSize { get { value = sizeAnchor.size; } };
8726
8727    property Anchor anchor
8728    {
8729       property_category $"Layout"
8730       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8731
8732       set
8733       {
8734          if(value != null)
8735          {
8736             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8737             {
8738                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8739                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8740             }
8741             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8742             {
8743                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8744                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8745             }
8746             anchor = value;
8747
8748             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
8749             {
8750                anchor.left.distance = 0;
8751                anchor.horz.type = 0;
8752             }
8753             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8754             {
8755                anchor.top.distance = 0;
8756                anchor.vert.type = 0;
8757             }
8758
8759             anchored = true;
8760
8761             //if(created)
8762             {
8763                int x, y, w, h;
8764
8765                normalAnchor = anchor;
8766                
8767                // Break the anchors for moveable/resizable windows
8768                /*if(style.fixed ) //&& value.left.type == cascade)
8769                {
8770                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8771
8772                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8773                   normalSizeAnchor = SizeAnchor { { w, h } };
8774                   anchored = false;
8775                }*/
8776                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8777                {
8778                   stateAnchor = normalAnchor;
8779                   stateSizeAnchor = normalSizeAnchor;
8780
8781                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8782                   Position(x, y, w, h, true, true, true, true, false, true);
8783                }
8784             }
8785          }
8786          else
8787          {
8788             anchored = false;
8789          }
8790       }
8791       get { value = this ? anchor : Anchor { }; }
8792    };
8793
8794    property Point position
8795    {
8796       property_category $"Layout"
8797       set
8798       {
8799          if(value == null) return;
8800
8801          anchor.left = value.x;
8802          anchor.top  = value.y;
8803          anchor.right.type = none;
8804          anchor.bottom.type = none;
8805          //if(created)
8806          {
8807             int x, y, w, h;
8808
8809             normalAnchor = anchor;
8810
8811             // Break the anchors for moveable/resizable windows
8812             /*
8813             if(style.fixed)
8814             {
8815                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8816
8817                normalAnchor.left = x;
8818                normalAnchor.top = y;
8819                normalAnchor.right.type = none;
8820                normalAnchor.bottom.type = none;
8821                normalSizeAnchor.size.width = w;
8822                normalSizeAnchor.size.height = h;
8823                anchored = false;
8824             }
8825             */
8826             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8827             {
8828                stateAnchor = normalAnchor;
8829                stateSizeAnchor = normalSizeAnchor;
8830
8831                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8832                Position(x,y, w, h, true, true, true, true, false, true);
8833             }
8834          }
8835       }
8836       get { value = position; }
8837    };
8838
8839    property bool disabled
8840    {
8841       property_category $"Behavior"
8842       set
8843       {
8844          if(this && disabled != value)
8845          {
8846             disabled = value;
8847             if(created)
8848                Update(null);
8849          }
8850       }
8851       get { return (bool)disabled; }
8852    };
8853
8854    property bool isEnabled
8855    {
8856       get
8857       {
8858          Window parent;
8859          for(parent = this; parent; parent = parent.parent)
8860             if(parent.disabled)
8861                return false;
8862          return true;
8863       }
8864    };
8865
8866    property WindowState state
8867    {
8868       property_category $"Behavior"
8869       set { SetState(value, false, 0); }
8870       get { return this ? state : 0; }
8871    };
8872
8873    property bool visible
8874    {
8875       property_category $"Behavior"
8876       set
8877       {
8878          if(this && !value && !style.hidden && parent)
8879          {
8880             bool wasActiveChild = parent.activeChild == this;
8881             Window client = null;
8882
8883             style.hidden = true;
8884             if(style.isActiveClient)
8885             {
8886                parent.numPositions--;
8887                if(state == minimized) parent.numIcons--;
8888             }
8889
8890             if(created)
8891             {
8892                OldLink prevOrder = null;
8893
8894                if(rootWindow == this)
8895                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8896                else
8897                {
8898                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8899                   if(style.nonClient)
8900                   {
8901                      box.left   -= parent.clientStart.x;
8902                      box.top    -= parent.clientStart.y;
8903                      box.right  -= parent.clientStart.x;
8904                      box.bottom -= parent.clientStart.y;
8905                   }
8906                   parent.Update(box);
8907                }
8908                if(_isModal && master && master.modalSlave == this)
8909                   master.modalSlave = null;
8910
8911                if(order)
8912                {
8913                   OldLink tmpPrev = order.prev;
8914                   client = tmpPrev ? tmpPrev.data : null;
8915                   if(client && !client.style.hidden && !client.destroyed && client.created)
8916                      prevOrder = tmpPrev;
8917                   for(;;)
8918                   {
8919                      client = tmpPrev ? tmpPrev.data : null;
8920                      if(client == this) { client = null; break; }
8921                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8922                      {
8923                         tmpPrev = client.order.prev;
8924                      }
8925                      else
8926                      {
8927                         if(client)
8928                            prevOrder = tmpPrev;
8929                         break;
8930                      }
8931                   }
8932
8933                   // If this window can be an active client, make sure the next window we activate can also be one
8934                   if(!style.nonClient && style.isActiveClient)
8935                   {
8936                      tmpPrev = prevOrder;
8937                      for(;;)
8938                      {
8939                         client = tmpPrev ? tmpPrev.data : null;
8940                         if(client == this) { client = null; break; }
8941                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8942                         {
8943                            tmpPrev = client.order.prev;
8944                         }
8945                         else 
8946                         {
8947                            if(client)
8948                               prevOrder = tmpPrev;
8949                            break;
8950                         }
8951                      }
8952                      if(client && client.style.hidden) client = null;
8953                   }
8954                }
8955
8956                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
8957                {
8958                   if(order && prevOrder && prevOrder.data != this)
8959                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8960                   else
8961                      ActivateEx(false, false, false, true, null, null);
8962
8963                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8964                   if(parent.activeClient == this)
8965                   {
8966                      parent.activeClient = null;
8967                      parent.UpdateActiveDocument(null);
8968                   }
8969                }
8970                else if(parent.activeClient == this)
8971                {
8972                   parent.activeClient = client;
8973                   parent.UpdateActiveDocument(this);
8974                }
8975
8976                // *** Not doing this anymore ***
8977               /*
8978                if(cycle)
8979                   parent.childrenCycle.Delete(cycle);
8980                if(order)
8981                   parent.childrenOrder.Delete(order);
8982                cycle = null;
8983                order = null;
8984                */
8985                
8986                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8987             }
8988
8989             firewatchers;
8990          }
8991          else if(this && value && style.hidden)
8992          {
8993             style.hidden = false;
8994             if(created)
8995             {
8996                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8997                if(rootWindow == this)
8998                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
8999
9000                if(_isModal && master)
9001                   master.modalSlave = this;
9002
9003                if(style.isActiveClient)
9004                {
9005                   positionID = parent.GetPositionID(this);
9006                   parent.numPositions++;
9007                   if(state == minimized) parent.numIcons++;
9008                }
9009
9010                // *** NOT DOING THIS ANYMORE ***
9011                /*
9012                if(!(style.inactive))
9013                {
9014                   if(!(style.noCycle))
9015                   {
9016                      cycle = parent.childrenCycle.AddAfter(
9017                         (parent.activeChild && parent.activeChild.cycle) ? 
9018                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
9019                      cycle.data = this;
9020                   }
9021                   order = parent.childrenOrder.AddAfter(
9022                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
9023                      sizeof(OldLink));
9024                   order.data = this;
9025                }
9026                */
9027      
9028                /*
9029                if(true || !parent.activeChild)
9030                   ActivateEx(true, false, true, true, null, null);
9031                */
9032                if(creationActivation == activate)
9033                   ActivateEx(true, false, true, true, null, null);
9034                else if(creationActivation == flash && !object)
9035                   Flash();               
9036
9037                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9038                Update(null);
9039
9040                // rootWindow.
9041                ConsequentialMouseMove(false);
9042             }
9043
9044             firewatchers;
9045          }
9046          else if(this)
9047             style.hidden = !value;
9048       }
9049
9050       get { return (style.hidden || !setVisible) ? false : true; }
9051    };
9052     
9053    property bool isDocument
9054    {
9055       property_category $"Document"
9056       set { style.isDocument = value; }
9057       get { return style.isDocument; }
9058    };
9059
9060    property bool mergeMenus
9061    {
9062       property_category $"Window Style"
9063       set { mergeMenus = value; }
9064       get { return (bool)mergeMenus; }
9065    };
9066
9067    property bool hasHorzScroll
9068    {
9069       property_category $"Window Style"
9070       set
9071       {
9072          if(value)
9073          {
9074             if(!style.hasHorzScroll && created)
9075             {
9076                CreateSystemChildren();         
9077                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9078             }
9079          }
9080          else if(style.hasHorzScroll)
9081          {
9082             sbh.Destroy(0);
9083             sbh = null;
9084             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9085          }
9086          style.hasHorzScroll = value;
9087       }
9088
9089       get { return style.hasHorzScroll; }
9090    };
9091
9092    property bool hasVertScroll
9093    {
9094       property_category $"Window Style"
9095       set
9096       {
9097          if(value)
9098          {
9099             if(!style.hasVertScroll && created)
9100             {
9101                style.hasVertScroll = true;
9102                CreateSystemChildren();
9103                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9104             }
9105          }
9106          else if(style.hasVertScroll)
9107          {
9108             sbv.Destroy(0);
9109             sbv = null;
9110             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9111          }
9112          style.hasVertScroll = value;
9113       }
9114       get { return style.hasVertScroll; }
9115    };
9116
9117    property bool dontHideScroll
9118    {
9119       property_category $"Behavior"
9120       set
9121       {
9122          scrollFlags.dontHide = value;
9123          if(value)
9124          {
9125             //UpdateScrollBars(true, true);
9126             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9127          }
9128          else
9129          {
9130             // UpdateScrollBars(true, true);
9131             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9132          }
9133       }
9134       get { return scrollFlags.dontHide; }
9135    };
9136
9137    property bool dontScrollVert
9138    {
9139       property_category $"Behavior"
9140       set { style.dontScrollVert = value; }
9141       get { return style.dontScrollVert; }
9142    };
9143    property bool dontScrollHorz
9144    {
9145       property_category $"Behavior"
9146       set { style.dontScrollHorz = value; }
9147       get { return style.dontScrollHorz; }
9148    };
9149
9150    property bool snapVertScroll
9151    {
9152       property_category $"Behavior"
9153       set
9154       {
9155          scrollFlags.snapY = value;
9156          if(sbv) sbv.snap = value;
9157       }
9158       get { return scrollFlags.snapY; }
9159    };
9160    property bool snapHorzScroll
9161    {
9162        property_category $"Behavior"
9163       set
9164       {
9165          scrollFlags.snapX = value;
9166          if(sbh) sbh.snap = value;
9167       }
9168       get { return scrollFlags.snapX; }
9169    };
9170
9171    property Point scroll
9172    {
9173       property_category $"Behavior"
9174       set { SetScrollPosition(value.x, value.y); }
9175       get { value = scroll; }
9176    };
9177
9178    property bool modifyVirtualArea
9179    {
9180       property_category $"Behavior"
9181       set { modifyVirtArea = value; }
9182       get { return (bool)modifyVirtArea; }
9183    };
9184
9185    property bool dontAutoScrollArea
9186    {
9187       property_category $"Behavior"
9188       // Activating a child control out of view will automatically scroll to make it in view
9189       set { noAutoScrollArea = value; }
9190       get { return (bool)noAutoScrollArea; }
9191    };
9192
9193    property char * fileName
9194    {
9195       property_category $"Document"
9196       set
9197       {
9198          if(menu && ((!fileName && value) || (fileName && !value)))
9199          {
9200             MenuItem item = menu.FindItem(MenuFileSave, 0);
9201             if(item) item.disabled = !modifiedDocument && value;
9202          }
9203
9204          delete fileName;
9205
9206          if(value && value[0])
9207             fileName = CopyString(value);
9208
9209          if(parent && this == parent.activeClient)
9210             parent.UpdateActiveDocument(null);
9211          else
9212             UpdateCaption();
9213
9214          // if(style.isDocument)
9215          if(!saving)
9216             fileMonitor.fileName = value;
9217       }
9218       get { return fileName; }
9219    };
9220
9221    property int64 id
9222    {
9223       property_category $"Data"
9224       set { id = value; }
9225       get { return id; }
9226    };
9227
9228    property bool modifiedDocument
9229    {
9230       property_category $"Document"
9231       set
9232       {
9233          if(style.isDocument || fileName)
9234          {
9235             if(menu)
9236             {
9237                MenuItem item = menu.FindItem(MenuFileSave, 0);
9238                if(item) item.disabled = !value && fileName;
9239             }
9240          }
9241
9242          if(modifiedDocument != value)
9243          {
9244             modifiedDocument = value;
9245             if(style.isDocument || fileName)
9246                UpdateCaption();
9247          }
9248       }
9249       get { return (bool)modifiedDocument; }
9250    };
9251
9252    property bool showInTaskBar
9253    {
9254       property_category $"Window Style"
9255       set { style.showInTaskBar = value; }
9256       get { return (style.showInTaskBar; }
9257    };
9258    property FileDialog saveDialog { set { saveDialog = value; } };
9259    property bool isActiveClient
9260    {
9261       property_category $"Behavior"
9262       set { style.isActiveClient = value; }
9263       get { return style.isActiveClient; }
9264    };
9265
9266    property Cursor cursor
9267    {
9268       property_category $"Appearance"
9269       set
9270       {
9271          cursor = value;
9272          SelectMouseCursor();
9273       }
9274       get { return cursor; }
9275    };      
9276
9277 //#if !defined(ECERE_VANILLA)
9278    property char * name
9279    {
9280       property_category $"Design"
9281       get
9282       {
9283          return (this && object) ? object.name : null;
9284       }
9285       set
9286       {
9287          if(activeDesigner)
9288             activeDesigner.RenameObject(object, value);
9289       }
9290    };
9291 //#endif
9292    property char * displayDriver
9293    {
9294       property_category $"Behavior"
9295       set
9296       {
9297          dispDriver = GetDisplayDriver(value);
9298          //DisplayModeChanged();
9299       }
9300       get
9301       {
9302          return dispDriver ? dispDriver.name : null;
9303       }
9304    }
9305
9306    // RUNTIME PROPERTIES
9307    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9308    property Size scrollArea
9309    {
9310       property_category $"Behavior"
9311       set
9312       {
9313          if(value != null)
9314             SetScrollArea(value.w, value.h, false);
9315          else
9316             SetScrollArea(0,0, true);
9317       }
9318       get { value = scrollArea; }
9319       isset
9320       {
9321          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9322       }
9323    };
9324    property bool is3D
9325    {
9326       property_category $"Layout"
9327       set { if(this) is3D = value; }
9328       get { return (bool)is3D; }
9329    };
9330
9331    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9332                                                                                                             
9333    // Will be merged with font later
9334    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9335    property Point clientStart { get { value = clientStart; } };
9336    property Point absPosition { get { value = absPosition; } };
9337    property Anchor normalAnchor { get {value = normalAnchor; } };
9338    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9339    property bool active { get { return (bool)active; } };
9340    property bool created { get { return (bool)created; } };
9341    property bool destroyed { get { return (bool)destroyed; } };
9342    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9343    property Window firstChild { get { return children.first; } };   
9344    property Window lastChild { get { return children.last; } };   
9345    property Window activeClient { get { return activeClient; } };
9346    property Window activeChild { get { return activeChild; } };
9347    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9348    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9349    property ScrollBar horzScroll { get { return sbh; } };
9350    property ScrollBar vertScroll { get { return sbv; } };
9351    property StatusBar statusBar { get { return statusBar; } };
9352    property Window rootWindow { get { return rootWindow; } };   
9353    property bool closing { get { return (bool)closing; } set { closing = value; } };
9354    property int documentID { get { return documentID; } };
9355    property Window previous { get { return prev; } }
9356    property Window next { get { return next; } }
9357    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9358    property PopupMenu menuBar { get { return menuBar; } }
9359    property ScrollBar sbv { get { return sbv; } }
9360    property ScrollBar sbh { get { return sbh; } }
9361    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9362    property void * systemHandle { get { return windowHandle; } }
9363    property Button minimizeButton { get { return sysButtons[0]; } };
9364    property Button maximizeButton { get { return sysButtons[1]; } };   
9365    property Button closeButton { get { return sysButtons[2]; } };
9366    property BitmapResource icon
9367    {
9368       get { return icon; }
9369       set
9370       {
9371          icon = value;
9372          if(icon) incref icon;
9373          if(created)
9374             guiApp.interfaceDriver.SetIcon(this, value);
9375       }
9376    };
9377    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9378    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9379    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9380    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9381    property bool nativeDecorations
9382    {
9383       get { return (bool)nativeDecorations; }
9384       set { nativeDecorations = value; }
9385 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9386       isset
9387       {
9388          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9389          bool result = false;
9390          if(nativeDecorations)
9391          {
9392             if(rootWindow == this)
9393                result = true;
9394             else
9395             {
9396                if(formDesigner && activeDesigner)
9397                {
9398                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9399                   Window form = cd ? cd.form : null;
9400                   if(form && parent == form.parent)
9401                      result = true;
9402                }
9403             }
9404          }
9405          return result != style.fixed;
9406       }
9407 #endif
9408    };
9409    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9410
9411    property char * text
9412    {
9413       property_category $"Deprecated"
9414       watchable
9415       set { property::caption = value; }
9416       get { return property::caption; }
9417    }
9418 private:
9419    // Data
9420    //char * yo;
9421    Window prev, next;
9422    WindowBits style;       // Window Style
9423    char * caption;            // Name / Caption
9424    Window parent;    // Parent window
9425    OldList children;          // List of children in Z order
9426    Window activeChild;     // Child window having focus
9427    Window activeClient;
9428    Window previousActive;  // Child active prior to activating the default child
9429    Window master;          // Window owning and receiving notifications concerning this window
9430    OldList slaves;            // List of windows belonging to this window
9431    Display display;        // Display this window is drawn into
9432
9433    Point position;         // Position in parent window client area
9434    Point absPosition;      // Absolute position
9435    Point clientStart;      // Client area position from (0,0) in this window
9436    Size size;              // Size
9437    Size clientSize;        // Client area size
9438    Size scrollArea;        // Virtual Scroll area size
9439    Size reqScrollArea;     // Requested virtual area size
9440    Point scroll;           // Virtual area scrolling position
9441    ScrollBar sbh, sbv;        // Scrollbar window handles
9442    Cursor cursor;        // Mouse cursor used for this window
9443    WindowState state;
9444    PopupMenu menuBar;
9445    StatusBar statusBar;
9446    Button sysButtons[3];
9447    char * fileName;
9448    Box clientArea;         // Client Area box clipped to parent
9449    Key setHotKey;
9450    HotKeySlot hotKey;        // HotKey for this window
9451    int numDocuments;
9452    int numPositions;
9453    Menu menu;
9454    ScrollFlags scrollFlags;// Window Scrollbar Flags
9455    int64 id;                 // Control ID
9456    int documentID;
9457    ColorAlpha background;  // Background color used to draw the window area
9458    Color foreground;
9459    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9460    OldList childrenCycle;     // Cycling order
9461    OldLink cycle;             // Element of parent's cycling order
9462    OldList childrenOrder;     // Circular Z-Order
9463    OldLink order;             // Element of parent's circular Z-Order
9464    Window modalSlave;      // Slave window blocking this window's interaction
9465
9466    Window rootWindow;      // Topmost system managed window
9467    void * windowHandle;    // System window handle
9468
9469    DialogResult returnCode;// Return code for modal windows
9470   
9471    Point sbStep;           // Scrollbar line scrolling steps
9472
9473    Anchor stateAnchor;
9474    SizeAnchor stateSizeAnchor;
9475
9476    Anchor normalAnchor;
9477    SizeAnchor normalSizeAnchor;
9478
9479    Size skinMinSize;       // Minimal window size based on style
9480    Point scrolledPos;      // Scrolled position
9481    Box box;                // Window box clipped to parent
9482    Box * against;          // What to clip the box to
9483
9484    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9485    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9486    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9487    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9488    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9489    Point scrolledArea;     // Distance to scroll area by
9490    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9491
9492    OldList hotKeys;           // List of the hotkeys of all children
9493    Window defaultControl;  // Default child control
9494    Size minSize;
9495    Size maxSize;
9496
9497    ColorAlpha * palette;   // Color palette used for this window
9498
9499    int caretSize;          // Size of caret, non zero if a caret is present
9500    Point caretPos;         // Caret position
9501
9502    void * systemParent;    // Parent System Window for embedded windows
9503
9504    int iconID;
9505    int numIcons;
9506    int positionID;
9507
9508    Mutex mutex;
9509    WindowState lastState;
9510
9511    FileMonitor fileMonitor
9512    {
9513       this, FileChange { modified = true };
9514
9515       bool OnFileNotify(FileChange action, char * param)
9516       {
9517          incref this;
9518          fileMonitor.StopMonitoring();
9519          if(OnFileModified(action, param))
9520             fileMonitor.StartMonitoring();
9521          delete this;
9522          return true;
9523       }
9524    };
9525    FontResource setFont, systemFont;
9526    FontResource usedFont;
9527    FontResource captionFont;
9528    OldList resources;
9529    FileDialog saveDialog;
9530    Anchor anchor;
9531    SizeAnchor sizeAnchor;
9532
9533    // FormDesigner data
9534    ObjectInfo object;
9535    Window control;
9536    Extent * tempExtents; //[4];
9537    BitmapResource icon;
9538    void * windowData;
9539    CreationActivationOption creationActivation;
9540    struct
9541    {
9542       bool active:1;            // true if window and ancestors are active
9543       bool acquiredInput:1;     // true if the window is processing state based input
9544       bool modifiedDocument:1;
9545       bool disabled:1;          // true if window cannot interact
9546       bool isForegroundWindow:1;// true while a root window is being activated
9547       bool visible:1;           // Visibility flag
9548       bool destroyed:1;         // true if window is being destroyed
9549       bool anchored:1;          // true if this window is repositioned when the parent resizes
9550       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9551       bool mouseInside:1;
9552       bool positioned:1;
9553       bool created:1;
9554       bool is3D:1;
9555       bool mergeMenus:1;
9556       bool modifyVirtArea:1;
9557       bool noAutoScrollArea:1;
9558       bool closing:1;
9559       bool autoCreate:1;
9560       bool setVisible:1;      // FOR FORM DESIGNER
9561       bool wasCreated:1;
9562       bool fullRender:1;
9563       bool moveable:1;
9564       bool alphaBlend:1;
9565       bool composing:1;
9566       bool useSharedMemory:1;
9567       bool resized:1;
9568       bool saving:1;
9569       bool nativeDecorations:1;
9570       bool manageDisplay:1;
9571       bool formDesigner:1; // True if we this is running in the form editor
9572    }; 
9573
9574    // Checks used internally for them not to take effect in FormDesigner
9575    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9576    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9577
9578    WindowController controller;
9579    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9580 };
9581
9582 public class CommonControl : Window
9583 {
9584    // creationActivation = doNothing;
9585
9586    ToolTip toolTip;
9587    public property String toolTip
9588    {
9589       property_category $"Appearance"
9590       set
9591       {
9592          if(created) CommonControl::OnDestroy();
9593          delete toolTip;
9594          toolTip = value ? ToolTip { tip = value; } : null;
9595          incref toolTip;
9596          if(created) CommonControl::OnCreate();
9597       }
9598       get { return toolTip ? toolTip.tip : null; }
9599    }
9600
9601    void OnDestroy()
9602    {
9603       if(toolTip)
9604          // (Very) Ugly work around for the fact that the parent watcher
9605          // won't fire when it's already been disconnected...
9606          eInstance_FireSelfWatchers(toolTip,
9607             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9608    }
9609
9610    bool OnCreate()
9611    {
9612       if(toolTip)
9613          toolTip.parent = this;
9614       return true;
9615    }
9616    ~CommonControl()
9617    {
9618       delete toolTip;
9619    }
9620 };
9621
9622 public class Percentage : float
9623 {
9624    char * OnGetString(char * string, float * fieldData, bool * needClass)
9625    {
9626       int c;
9627       int last = 0;
9628       sprintf(string, "%.2f", this);
9629       c = strlen(string)-1;
9630       for( ; c >= 0; c--)
9631       {
9632          if(string[c] != '0') 
9633             last = Max(last, c);
9634          if(string[c] == '.')
9635          {
9636             if(last == c)
9637                string[c] = 0;
9638             else
9639                string[last+1] = 0;
9640             break;
9641          }
9642       }
9643       return string;
9644    }
9645 };
9646
9647 public void ApplySkin(Class c, char * name, void ** vTbl)
9648 {
9649    char className[1024];
9650    Class sc;
9651    OldLink d;
9652    int m;
9653
9654    subclass(Window) wc = (subclass(Window))c;
9655    subclass(Window) base = (subclass(Window))c.base;
9656
9657    sprintf(className, "%sSkin_%s", name, c.name);
9658    wc.pureVTbl = c._vTbl;
9659    c._vTbl = new void *[c.vTblSize];
9660    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9661    sc = eSystem_FindClass(c.module.application, className);
9662    
9663    if(vTbl)
9664    {
9665       for(m = 0; m < c.base.vTblSize; m++)
9666       {
9667          if(c._vTbl[m] == base.pureVTbl[m])
9668             c._vTbl[m] = vTbl[m];
9669       }
9670    }
9671    if(sc)
9672    {
9673       for(m = 0; m < c.vTblSize; m++)
9674       {
9675          if(sc._vTbl[m] != wc.pureVTbl[m])
9676             c._vTbl[m] = sc._vTbl[m];
9677       }
9678    }
9679       
9680    for(d = c.derivatives.first; d; d = d.next)
9681    {
9682       ApplySkin(d.data, name, c._vTbl);
9683    }
9684 }
9685
9686 public void UnapplySkin(Class c)
9687 {
9688    char className[1024];
9689    Class sc;
9690    subclass(Window) wc = (subclass(Window))c;
9691    subclass(Window) base = (subclass(Window))c.base;
9692    OldLink d;
9693
9694    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9695    {
9696       delete c._vTbl;
9697       c._vTbl = wc.pureVTbl;
9698       wc.pureVTbl = null;
9699    }
9700
9701    for(d = c.derivatives.first; d; d = d.next)
9702    {
9703       UnapplySkin(d.data);
9704    }
9705 }
9706 /*
9707 void CheckFontIntegrity(Window window)
9708 {
9709    Window c;
9710    if(window)
9711    {
9712       if(window.usedFont && window.usedFont.font == 0xecececec)
9713       {
9714          FontResource uf = window.usedFont;
9715          char * className = window._class.name;
9716          char * text = window.text;
9717          Print("");
9718       }
9719       for(c = window.firstChild; c; c = c.next)
9720          CheckFontIntegrity(c);
9721    }
9722 }*/
9723
9724 public class ControllableWindow : Window
9725 {
9726    /*WindowController controller;
9727    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9728    ~ControllableWindow() { delete controller; }*/
9729 }
9730
9731 class WindowControllerInterface : ControllableWindow
9732 {
9733    bool OnKeyDown(Key key, unichar ch)
9734    {
9735       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch);
9736       if(result)
9737          result = ((bool (*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown])(controller.window, key, ch);
9738       return result;
9739    }
9740
9741    bool OnKeyUp(Key key, unichar ch)
9742    {
9743       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch);
9744       if(result)
9745          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp])(controller.window, key, ch);
9746       return result;
9747    }
9748
9749    bool OnKeyHit(Key key, unichar ch)
9750    {
9751       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch);
9752       if(result)
9753          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit])(controller.window, key, ch);
9754       return result;
9755    }
9756
9757    bool OnMouseMove(int x, int y, Modifiers mods)
9758    {
9759       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods);
9760       if(result)
9761          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove])(controller.window, x, y, mods);
9762       return result;
9763    }
9764
9765    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9766    {
9767       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods);
9768       if(result)
9769          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown])(controller.window, x, y, mods);
9770       return result;
9771    }
9772
9773    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9774    {
9775       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods);
9776       if(result)
9777          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp])(controller.window, x, y, mods);
9778       return result;
9779    }
9780
9781    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9782    {
9783       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9784       if(result)
9785          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick])(controller.window, x, y, mods);
9786       return result;
9787    }
9788
9789    bool OnRightButtonDown(int x, int y, Modifiers mods)
9790    {
9791       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods);
9792       if(result)
9793          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown])(controller.window, x, y, mods);
9794       return result;
9795    }
9796
9797    bool OnRightButtonUp(int x, int y, Modifiers mods)
9798    {
9799       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods);
9800       if(result)
9801          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp])(controller.window, x, y, mods);
9802       return result;
9803    }
9804
9805    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9806    {
9807       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9808       if(result)
9809          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick])(controller.window, x, y, mods);
9810       return result;
9811    }
9812
9813    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9814    {
9815       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods);
9816       if(result)
9817          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown])(controller.window, x, y, mods);
9818       return result;
9819    }
9820
9821    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9822    {
9823       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods);
9824       if(result)
9825          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp])(controller.window, x, y, mods);
9826       return result;
9827    }
9828
9829    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9830    {
9831       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9832       if(result)
9833          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick])(controller.window, x, y, mods);
9834       return result;
9835    }
9836
9837    void OnResize(int width, int height)
9838    {
9839       ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
9840       ((void(*)(Window, int, int))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize])(controller.window, width, height);
9841    }
9842
9843    void OnRedraw(Surface surface)
9844    {
9845       ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
9846       ((void(*)(Window, Surface))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(controller.window, surface);
9847    }
9848
9849    bool OnCreate()
9850    {
9851       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller);
9852       if(result)
9853          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate])(controller.window);
9854       return result;
9855    }
9856
9857    bool OnLoadGraphics()
9858    {
9859       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller);
9860       if(result)
9861          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics])(controller.window);
9862       return result;
9863    }
9864
9865    void OnUnloadGraphics()
9866    {
9867       ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
9868       ((void(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics])(controller.window);
9869    }
9870 }
9871
9872 public class WindowController<class V>
9873 {
9874 public:
9875    property Window window
9876    {
9877       set
9878       {
9879          uint size = class(Window).vTblSize;
9880          if(value)
9881          {
9882             windowVTbl = new void *[size];
9883             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9884             if(value._vTbl == value._class._vTbl)
9885             {
9886                value._vTbl = new void *[value._class.vTblSize];
9887                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9888             }
9889             {
9890                int c;
9891                for(c = 0; c < size; c++)
9892                {
9893                   void * function = class(WindowControllerInterface)._vTbl[c];
9894                   if(function != DefaultFunction)
9895                      value._vTbl[c] = function;
9896                   else
9897                      value._vTbl[c] = windowVTbl[c];
9898                }
9899             }
9900          }
9901          else
9902             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9903          window = value;
9904       }
9905       get { return window; }
9906    }
9907    property V controlled
9908    {
9909       set { controlled = value; }
9910       get { return controlled; }
9911    }
9912    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9913    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9914    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9915    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9916    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9917    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9918    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9919    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9920    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9921    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9922    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9923    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9924    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9925    virtual void V::OnResize(WindowController controller, int width, int height);
9926    virtual void V::OnRedraw(WindowController controller, Surface surface);
9927    virtual bool V::OnCreate(WindowController controller);
9928    virtual bool V::OnLoadGraphics(WindowController controller);
9929    virtual void V::OnUnloadGraphics(WindowController controller);
9930
9931 private:
9932    int (** windowVTbl)();   
9933    V controlled;
9934    Window window;
9935
9936    ~WindowController()
9937    {
9938       delete windowVTbl;
9939    }
9940 }