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