ecere: Activation/Maximization Fixes for Ecere Communicator
[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.FindLink(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             property::master = master.modalSlave;
5919             //return false;
5920
5921          if(parent)
5922             parent.children.Remove(this);
5923          if(master)
5924          {
5925             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
5926                if(slaveHolder.data == this)
5927                {
5928                   master.slaves.Delete(slaveHolder);
5929                   break;
5930                }
5931          }
5932
5933          if(parent == guiApp.desktop && !mutex)
5934             mutex = Mutex {};
5935
5936          if(style.isDocument)
5937          {
5938             if(parent)
5939                parent.numDocuments--;
5940             documentID = parent.GetDocumentID();
5941          }
5942
5943          if(!style.stayOnTop)
5944             for(; last && last.style.stayOnTop; last = last.prev);
5945
5946          parent.children.Insert((last == this) ? null : last, this);
5947          //parent.children.Add(this);
5948
5949          if(!dispDriver)
5950             dispDriver = parent.dispDriver;
5951          destroyed = false;
5952          if(style.modal)
5953             master.modalSlave = this;
5954
5955          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
5956
5957          incref this;
5958          incref this;
5959
5960          master.slaves.Add(slaveHolder = OldLink { data = this });
5961          if(slaveHolder)
5962          {
5963             if(setHotKey)
5964             {
5965                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
5966             }
5967             if(style.isDefault && !master.defaultControl)
5968                master.defaultControl = this;
5969
5970             stateAnchor = normalAnchor = anchor;
5971             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
5972
5973             // TOCHECK: Why is this here?
5974             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
5975             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
5976
5977             this.visible = false;
5978             style.hidden = true;
5979     
5980             //created = true;
5981             // autoCreate = true;
5982             wasCreated = true;
5983             if(SetupDisplay())
5984             {
5985                created = true;
5986                if(OnCreate())
5987                {
5988                   /*
5989                   if(parent == guiApp.desktop)
5990                      Log("LoadGraphics %s\n", caption);
5991                   */
5992                   if(LoadGraphics(true, false))
5993                   {
5994                      if(!setFont)
5995                      {
5996                         watch(parent)
5997                         {
5998                            font
5999                            {
6000                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
6001                               firewatchers font;
6002                               Update(null);
6003                            }
6004                         };
6005                      }
6006
6007                      if(style.hasMenuBar /*&& menu*/)
6008                      {
6009                         menuBar = 
6010                            PopupMenu
6011                            {
6012                               this,
6013                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
6014                               interim = false, inactive = true, nonClient = true, size.h = 24
6015                            };
6016                         menuBar.Create();
6017                      }
6018
6019                      if(statusBar)
6020                         statusBar.Create();
6021                      
6022                      // Create the system buttons
6023                      CreateSystemChildren();
6024
6025                      UpdateActiveDocument(null);
6026
6027                      if(style.isDocument)
6028                      {
6029                         if(menu)
6030                         {
6031                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6032                            if(item) item.disabled = !modifiedDocument && fileName;
6033                         }
6034                      }
6035
6036                      /*
6037                      if(parent == guiApp.desktop)
6038                         Log("Preemptive SetState %s\n", caption);
6039                      */
6040
6041                      // Preemptive Set State to ensure proper anchoring
6042                      SetStateEx(state, false);
6043                      /*
6044                      style.hidden = true;
6045                      visible = false;
6046                      */
6047
6048                      {
6049                         Window child, next;
6050                         for(child = children.first; child; child = next)
6051                         {
6052                            next = child.next;
6053                            if(!child.created && (child.autoCreate || child.wasCreated))
6054                               child.Create();
6055                         }
6056                      }
6057
6058                      {
6059                         OldLink link, next;
6060                         for(link = slaves.first; link; link = next)
6061                         {
6062                            Window slave = link.data;
6063                            next = link.next;
6064                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6065                               slave.Create();
6066                         }
6067                      }
6068
6069                      if(OnPostCreate())
6070                         OnApplyGraphics();
6071
6072                      /*
6073                      if(parent == guiApp.desktop)
6074                         Log("Real SetState %s\n", caption);
6075                      */
6076
6077                      if(isActiveClient && visible)
6078                      {
6079                         parent.numPositions--;
6080                         if(state == minimized) parent.numIcons--;
6081                      }
6082
6083                      // Real set state & activate for proper display & activation
6084                      property::visible = visible;
6085                      //  SetState(state & 0x00000003, true, 0);
6086
6087                      if(visible)
6088                      {
6089                         UpdateCaption();
6090                         /*if(rootWindow == this)
6091                            guiApp.interfaceDriver.ActivateRootWindow(this);
6092                         else*/
6093                         if(creationActivation == activate)
6094                            ActivateEx(true, false, true, true, null, null);
6095                         else if(creationActivation == flash)
6096                            Flash();
6097                      }
6098
6099                      if(!destroyed)
6100                         rootWindow.ConsequentialMouseMove(false);
6101
6102                      result = true;
6103                   }
6104                }
6105             }
6106          }
6107          /*
6108          if(!result)
6109          {
6110             Destroy(0);
6111             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6112          }
6113          */
6114
6115          if(!result)
6116          {
6117             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6118             created = false;
6119             //style.hidden = true; // !visible;
6120             style.hidden = !visible;
6121             if(master.modalSlave == this)
6122                master.modalSlave = null;
6123          }
6124          delete this;
6125       }
6126       return result;
6127    }
6128
6129    void WriteCaption(Surface surface, int x, int y)
6130    {
6131       if(caption)
6132          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6133    }
6134
6135    void Update(Box region)
6136    {
6137       if(this)
6138       {
6139          Window rootWindow;
6140
6141          rootWindow = this.rootWindow;
6142
6143          // rootWindow.mutex.Wait();
6144          if(!destroyed && visible && display)
6145          {
6146             Window child;
6147             Box realBox;
6148             
6149             // Testing this to avoid repetitve full update to take time...
6150             if(dirtyArea.count == 1)
6151             {
6152                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6153                if(item.box.left <= box.left &&
6154                   item.box.top <= box.top &&
6155                   item.box.right >= box.right &&
6156                   item.box.bottom >= box.bottom)
6157                {
6158                   rootWindow.dirty = true;
6159                   return;
6160                }
6161             }
6162
6163             if(display.flags.flipping && !rootWindow.dirty)
6164             {
6165                if(this == rootWindow)
6166                   region = null;
6167                else
6168                {
6169                   rootWindow.Update(null);
6170                   return;
6171                }
6172             }
6173             
6174             rootWindow.dirty = true;
6175
6176             if(region != null)
6177             {
6178                realBox = region;
6179                realBox.left += clientStart.x;
6180                realBox.top += clientStart.y;
6181                realBox.right += clientStart.x;
6182                realBox.bottom += clientStart.y;
6183                realBox.Clip(box);
6184             }
6185             else
6186                realBox = box;
6187
6188             if(realBox.right >= realBox.left && 
6189                realBox.bottom >= realBox.top)
6190             {
6191                // if(!rootWindow.fullRender)
6192                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6193
6194                for(child = children.first; child; child = child.next)
6195                {
6196                   if(!child.is3D)
6197                   {
6198                      Box box = realBox;
6199                      box.left -= child.absPosition.x - absPosition.x;
6200                      box.top -= child.absPosition.y - absPosition.y;
6201                      box.right -= child.absPosition.x - absPosition.x;
6202                      box.bottom -= child.absPosition.y - absPosition.y;
6203                      if(box.right >= child.box.left && box.left <= child.box.right &&
6204                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6205                      {
6206                         box.left -= child.clientStart.x;
6207                         box.top -= child.clientStart.y;
6208                         box.right -= child.clientStart.x;
6209                         box.bottom -= child.clientStart.y;
6210                         child.Update(box);
6211                      }
6212                   }
6213                }
6214
6215                realBox.left += absPosition.x - rootWindow.absPosition.x;
6216                realBox.top += absPosition.y - rootWindow.absPosition.y;
6217                realBox.right += absPosition.x - rootWindow.absPosition.x;
6218                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6219                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6220             }
6221          }
6222          else if(this == guiApp.desktop)
6223          {
6224             Window window;
6225             for(window = children.first; window; window = window.next)
6226             {
6227                if(!window.is3D)
6228                {
6229                   if(region != null)
6230                   {
6231                      Box childBox = region;
6232
6233                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6234                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6235                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6236                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6237        
6238                      window.Update(childBox);
6239                   }
6240                   else
6241                      window.Update(null);
6242                }
6243             }
6244          }
6245
6246          // rootWindow.mutex.Release();
6247       }
6248    }
6249
6250    bool Capture(void)
6251    {
6252       bool result = true;
6253       if(guiApp.windowCaptured != this)
6254       {
6255          if(guiApp.windowCaptured)
6256             result = false;
6257          else
6258          {
6259             //Logf("Captured %s (%s)\n", caption, class.name);
6260             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6261             guiApp.windowCaptured = this;
6262          }
6263       }
6264       return result;
6265    }
6266
6267    bool Destroy(int code)
6268    {
6269       //if(created)
6270       if(this)
6271       {
6272          if(!CloseConfirmation(false)) return false;
6273          incref this;
6274          if(DestroyEx(code))
6275          {
6276             // TOCHECK: Should autoCreate be set to false here?
6277             autoCreate = false;
6278             wasCreated = false;
6279             // Is this needed here? DestroyEx should decref already...
6280             delete this;
6281             return true;
6282          }
6283          delete this;
6284       }
6285       return false;
6286    }
6287
6288    void Move(int x, int y, int w, int h)
6289    {
6290       normalAnchor = Anchor { left = x, top = y };
6291       normalSizeAnchor = SizeAnchor { size = { w, h } };
6292
6293       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6294       {
6295          if(destroyed) return;
6296
6297          stateAnchor = normalAnchor;
6298          stateSizeAnchor = normalSizeAnchor;
6299
6300          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6301          Position(x,y, w, h, true, true, true, true, false, true);
6302       }
6303    }
6304
6305    DialogResult Modal(void)
6306    {
6307       isModal = true;
6308       if(Create())
6309          return DoModal();
6310
6311       // FIXES MEMORY LEAK IF Create() FAILED
6312       incref this;
6313       delete this;
6314       return 0;
6315    }
6316
6317    void SetScrollArea(int width, int height, bool snapToStep)
6318    {
6319       bool resize = false;
6320       if(snapToStep)
6321       {
6322          int stepX = sbStep.x, stepY = sbStep.y;
6323          // Needed to make snapped down position match the skin's check of client area 
6324          // against realvirtual
6325          if(guiApp.textMode)
6326          {
6327             SNAPDOWN(stepX, textCellW);
6328             SNAPDOWN(stepY, textCellH);
6329             stepX = Max(stepX, textCellW);
6330             stepY = Max(stepY, textCellH);
6331          }
6332          if(scrollFlags.snapX)
6333             SNAPUP(width, stepX);
6334          if(scrollFlags.snapY)
6335             SNAPUP(height, stepY);
6336       }
6337
6338       reqScrollArea.w = width;
6339       reqScrollArea.h = height;
6340       noAutoScrollArea = (width > 0 || height > 0);
6341
6342       UpdateScrollBars(true, true);
6343    }
6344
6345    void SetScrollPosition(int x, int y)
6346    {
6347       if(sbh)
6348          sbh.Action(setPosition, x, 0);
6349       else
6350       {
6351          int range;
6352          int seen = clientSize.w, total = reqScrollArea.w;
6353          seen = Max(1,seen);
6354          if(scrollFlags.snapX)
6355             SNAPDOWN(seen, sbStep.x);
6356
6357          if(!total) total = seen;
6358          range = total - seen + 1;
6359          range = Max(range, 1);
6360          if(x < 0) x = 0;
6361          if(x >= range) x = range - 1;
6362
6363          if(scrollFlags.snapX)
6364             SNAPUP(x, sbStep.x);
6365
6366          if(scroll.x != x)
6367             OnHScroll(setPosition, x, 0);
6368
6369          if(guiApp.textMode)
6370          {
6371             SNAPDOWN(x, textCellW);
6372          }
6373          scroll.x = x;
6374       }
6375
6376       if(sbv)
6377          sbv.Action(setPosition, y, 0);
6378       else
6379       {
6380          int range;
6381          int seen = clientSize.h, total = reqScrollArea.h;
6382          seen = Max(1,seen);
6383
6384          if(scrollFlags.snapY)
6385             SNAPDOWN(seen, sbStep.y);
6386
6387          if(!total) total = seen;
6388          range = total - seen + 1;
6389          range = Max(range, 1);
6390          if(y < 0) y = 0;
6391          if(y >= range) y = range - 1;
6392
6393          if(scrollFlags.snapY)
6394             SNAPUP(y, sbStep.y);
6395
6396          if(scroll.y != y)
6397             OnVScroll(setPosition, y, 0);
6398          if(guiApp.textMode)
6399          {
6400             SNAPDOWN(y, textCellH);
6401          }
6402          scroll.y = y;
6403       }
6404       if(!sbh || !sbv)
6405          UpdateCaret(false, false);
6406    }
6407
6408    void SetScrollLineStep(int stepX, int stepY)
6409    {
6410       sbStep.x = stepX;
6411       sbStep.y = stepY;
6412       if(guiApp.textMode)
6413       {
6414          SNAPDOWN(stepX, textCellW);
6415          SNAPDOWN(stepY, textCellH);
6416          stepX = Max(stepX, textCellW);
6417          stepY = Max(stepY, textCellH);
6418       }
6419       if(sbh)
6420          sbh.lineStep = stepX;
6421       if(sbv)
6422          sbv.lineStep = stepY;
6423    }
6424
6425    void SetState(WindowState newState, bool activate, Modifiers mods)
6426    {
6427       if(created)
6428       {
6429          if(state == newState || OnStateChange(newState, mods))
6430          {
6431             WindowState prevState = state;
6432
6433             StopMoving();
6434
6435             // This used to be at the end of the brackets... moved for X, testing...
6436             // This has the effect of activating the window through the system...
6437             if(rootWindow == this)
6438                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6439       
6440             SetStateEx(newState, activate);
6441
6442             if(rootWindow == this && !rootWindow.nativeDecorations)
6443             {
6444                int x = position.x, y = position.y;
6445                /*if(style.interim)
6446                {
6447                   x -= guiApp.desktop.absPosition.x;
6448                   y -= guiApp.desktop.absPosition.y;
6449                }*/
6450                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6451             }
6452
6453             //state = newState;
6454             //state = prevState;
6455
6456             if(state != maximized && style.hasMaximize)
6457             {
6458                Window child;
6459                for(child = parent.children.first; child; child = child.next)
6460                {
6461                   if(child != this && child.state == maximized)
6462                      child.SetStateEx(normal, false);
6463                }
6464             }
6465
6466             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6467                parent.UpdateScrollBars(true, true);
6468
6469             /*
6470             // Do we really need this stuff here? 
6471             // Shouldn't the Activate stuff take care of it?              
6472             if(parent.rootWindow == parent && style)
6473             {
6474                char caption[2048];
6475                parent.FigureCaption(caption);
6476                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6477                parent.UpdateDecorations();
6478             }         
6479             */
6480
6481             rootWindow.ConsequentialMouseMove(false);
6482          }
6483       }
6484       else
6485          state = newState;
6486    }
6487
6488    BitmapResource GetIcon(SkinBitmap iconID)
6489    {
6490       return guiApp.currentSkin.GetBitmap(iconID);
6491    }
6492
6493    void SetMouseRange(Box range)
6494    {
6495       if(range || guiApp.fullScreenMode)
6496       {
6497          Box clip;
6498          if(range != null)
6499          {
6500             clip.left   = range.left + absPosition.x + clientStart.x;
6501             clip.top    = range.top + absPosition.y + clientStart.y;
6502             clip.right  = range.right + absPosition.x + clientStart.x;
6503             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6504          }
6505          else
6506          {
6507             clip.left   = guiApp.desktop.box.left;
6508             clip.top    = guiApp.desktop.box.top;
6509             clip.right  = guiApp.desktop.box.right;
6510             clip.bottom = guiApp.desktop.box.bottom;
6511          }
6512          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6513       }
6514       else
6515          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6516    }
6517
6518    void SetMouseRangeToClient(void)
6519    {
6520       if(guiApp.fullScreenMode || this != guiApp.desktop)
6521       {
6522          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6523          box.Clip(clientArea);
6524          SetMouseRange(box);
6525       }
6526       else
6527          SetMouseRange(null);
6528    }
6529
6530    void SetMouseRangeToWindow(void)
6531    {
6532       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6533       if(this == guiApp.desktop)
6534          SetMouseRangeToClient();
6535       else
6536          SetMouseRange(box);
6537    }
6538
6539    // x, y: Desktop Coordinates
6540    void ShowSysMenu(int x, int y)
6541    {
6542       Menu menu { };
6543       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6544       MenuItem
6545       {
6546          menu, "Restore", r, NotifySelect = MenuWindowRestore, 
6547          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6548       };
6549       MenuItem
6550       {
6551          menu, "Move", m, NotifySelect = MenuWindowMove, 
6552          disabled = !style.fixed || state == maximized
6553       };
6554       MenuItem
6555       {
6556          menu, "Size", s, NotifySelect = MenuWindowSize, 
6557          disabled = !style.sizable || state != normal
6558       };
6559       MenuItem
6560       {
6561          menu, "Minimize", n, NotifySelect = MenuWindowMinimize, 
6562          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6563       };
6564       MenuItem
6565       {
6566          menu, "Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize, 
6567          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6568       };
6569       MenuItem
6570       {
6571          menu, "Stay On Top", t, NotifySelect = MenuWindowStayOnTop, 
6572          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6573       };
6574       MenuDivider { menu };
6575       MenuItem
6576       {
6577          menu, "Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6578          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6579       };
6580       windowMenu.Create();
6581    }
6582
6583    void Activate(void)
6584    {
6585       ActivateEx(true, true, true, true, null, null);
6586    }
6587
6588    void MakeActive(void)
6589    {
6590       ActivateEx(true, false, true, false, null, null);
6591    }
6592
6593    void SoftActivate(void)
6594    {
6595       if(guiApp.desktop.active)
6596          Activate();
6597       else if(!active)
6598          Flash();
6599    }
6600
6601    void Deactivate(void)
6602    {
6603       ActivateEx(false, true, true, true, null, null);
6604    }
6605
6606    void Flash(void)
6607    {
6608       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6609    }
6610
6611    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6612    {
6613       bool result = false;
6614       if(activeChild && activeChild.cycle)
6615       {
6616          Window modalWindow, child = activeChild;
6617          if(!clientOnly /*&& parent.tabCycle*/)
6618          {
6619             Window next = child;
6620             while(true)
6621             {
6622                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6623                {
6624                   if(cycleParents)
6625                   {
6626                      if(parent && parent.CycleChildren(backward, false, true, true))
6627                         return true;
6628                      break;
6629                   }
6630                   else
6631                      return false;
6632                }
6633                if(backward)
6634                   next = next.cycle.prev.data;
6635                else
6636                   next = next.cycle.next.data;
6637                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6638                   break;
6639             }
6640          }
6641          /*
6642          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) && 
6643             parent.tabCycle && parent.CycleChildren(backward, false, false))
6644             return true;
6645          */
6646
6647          if(tabCycleOnly && !tabCycle) return false;
6648
6649          while(child)
6650          {
6651             while(true)
6652             {
6653                if(backward)
6654                   child = child.cycle.prev.data;
6655                else
6656                   child = child.cycle.next.data;
6657                if(child == child.parent.activeChild)
6658                   return result;
6659                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6660                   break;
6661             }
6662             modalWindow = child.FindModal();
6663             if(!modalWindow)
6664             {
6665                // Scroll the window to include the active control
6666                if(sbh && !child.style.dontScrollHorz)
6667                {
6668                   if(child.scrolledPos.x < 0)
6669                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6670                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6671                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6672                }
6673                if(sbv && !child.style.dontScrollVert)
6674                {
6675                   if(child.scrolledPos.y < 0)
6676                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6677                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6678                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6679                }
6680             }
6681             result = true;
6682             child = modalWindow ? modalWindow : child;
6683             child.ActivateEx(true, true, true, true, null, null);
6684             if(child.tabCycle && child.childrenCycle.first)
6685                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6686             else
6687                break;
6688          }
6689       }
6690       else
6691          return false;
6692
6693       ConsequentialMouseMove(false);
6694       return result;
6695    }
6696
6697    void AddResource(Resource resource)
6698    {
6699       if(resource)
6700       {
6701          ResPtr ptr { resource = resource };
6702          resources.Add(ptr);
6703          incref resource;
6704
6705          // Load Graphics here if window is created already
6706          if(/*created && */display)
6707          {
6708             display.Lock(false);
6709             ptr.loaded = display.displaySystem.LoadResource(resource);
6710             display.Unlock();
6711          }
6712          /*
6713          // Temporary hack to load font right away for listbox in dropbox ...
6714          else if(master && master.display)
6715          {
6716             master.display.Lock(false);
6717             master.display.displaySystem.LoadResource(resource);
6718             master.display.Unlock();
6719          }
6720          */
6721       }
6722    }
6723
6724    void RemoveResource(Resource resource)
6725    {
6726       if(resource)
6727       {
6728          ResPtr ptr;
6729          for(ptr = resources.first; ptr; ptr = ptr.next)
6730          {
6731             if(ptr.resource == resource)
6732                break;
6733          }
6734
6735          if(ptr)
6736          {
6737             // Unload Graphics here if window is created already
6738             if(/*created && */display)
6739             {
6740                if(ptr.loaded)
6741                {
6742                   display.Lock(false);
6743                   display.displaySystem.UnloadResource(resource, ptr.loaded);
6744                   display.Unlock();
6745                   ptr.loaded = null;
6746                }
6747             }
6748             delete resource;
6749             resources.Delete(ptr);
6750          }
6751       }
6752    }
6753
6754    void SetCaret(int x, int y, int size)
6755    {
6756       if(!destroyed)
6757       {
6758          caretPos.x = x;
6759          caretPos.y = y;
6760          caretSize = size;
6761          if(active && !style.interim)
6762          {
6763             if(visible || !guiApp.caretOwner)
6764                guiApp.caretOwner = size ? this : null;
6765             if(size)
6766                UpdateCaret(false, false);
6767             else
6768             {
6769                guiApp.interfaceDriver.SetCaret(0,0,0);
6770                UpdateCaret(false, true);
6771                guiApp.caretEnabled = false;
6772             }
6773          }
6774          else if(style.inactive && active)
6775          {
6776             guiApp.interfaceDriver.SetCaret(0,0,0);
6777             UpdateCaret(false, true);
6778             guiApp.caretEnabled = false;
6779          }
6780       }
6781    }
6782
6783    void Scroll(int x, int y)
6784    {
6785       bool opaque = !style.drawBehind || background.a;
6786       if(opaque && display && display.flags.scrolling)
6787       {
6788          Box box = clientArea;
6789          box.left += clientStart.x;
6790          box.top += clientStart.y;
6791          box.right += clientStart.x;
6792          box.bottom += clientStart.y;
6793
6794          //scrollExtent.Free(null);
6795          scrollExtent.AddBox(box);
6796          scrolledArea.x += x;
6797          scrolledArea.y += y;
6798
6799          //scrollExtent.Free();
6800          //scrollExtent.AddBox(clientArea);
6801          //scrollExtent.Offset(clientStart.x, clientStart.y);
6802          //scrolledArea.x = x;
6803          //scrolledArea.y = y;
6804       }
6805       else
6806          Update(clientArea);
6807
6808       if(rootWindow)
6809          rootWindow.dirty = true;
6810    }
6811
6812    void ReleaseCapture()
6813    {
6814       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
6815       {
6816          Window oldCaptured = guiApp.windowCaptured;
6817          guiApp.windowCaptured = null;
6818          guiApp.prevWindow = null;
6819          incref oldCaptured;
6820
6821          //guiApp.Log("Released Capture\n");
6822
6823          guiApp.interfaceDriver.SetMouseCapture(null);
6824
6825          //oldCaptured.OnMouseCaptureLost();
6826
6827          if(oldCaptured)
6828             oldCaptured.ConsequentialMouseMove(false);
6829          delete oldCaptured;
6830       }
6831    }
6832
6833    void SetText(char * format, ...)
6834    {
6835       if(this)
6836       {
6837          delete caption;
6838          if(format)
6839          {
6840             char caption[MAX_F_STRING];
6841             va_list args;
6842             va_start(args, format);
6843             vsprintf(caption, format, args);
6844             va_end(args);
6845
6846             this.caption = new char[strlen(caption)+1];
6847             if(this.caption)
6848                strcpy(this.caption, caption);
6849          }
6850          if(created)
6851             UpdateCaption();
6852
6853          firewatchers text;
6854       }
6855    }
6856
6857    bool Grab(Bitmap bitmap, Box box, bool decorations)
6858    {
6859       bool result = false;
6860       if(display || this == guiApp.desktop)
6861       {
6862          Box clip = {MININT, MININT, MAXINT, MAXINT};
6863
6864          if(box != null)
6865             clip = box;
6866
6867          if(!decorations)
6868             clip.Clip(clientArea);
6869          else
6870             clip.Clip(this.box);
6871
6872          if(rootWindow != this)
6873          {
6874             clip.left   += absPosition.y;
6875             clip.top    += absPosition.y;
6876             clip.right  += absPosition.x;
6877             clip.bottom += absPosition.y;
6878          }
6879
6880          clip.left += decorations ? 0 : clientStart.x;
6881          clip.top += decorations ? 0 : clientStart.y;
6882          clip.right += decorations ? 0 : clientStart.x;
6883          clip.bottom += decorations ? 0 : clientStart.y;
6884
6885          if(display && display.flags.flipping)
6886          {
6887             rootWindow.Update(null);
6888             rootWindow.UpdateDisplay();
6889          }
6890
6891          if(!display)
6892          {
6893             Window window { };
6894             window.Create();
6895             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
6896                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
6897             delete window;
6898          }
6899          else
6900             result = display.Grab(bitmap, clip.left, clip.top, 
6901                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
6902
6903          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
6904          {
6905             if(!bitmap.Convert(null, pixelFormat888, null))
6906                result = false;
6907          }
6908       }
6909       return result;
6910    }
6911
6912    void GetMousePosition(int * x, int * y)
6913    {
6914       int mouseX = 0, mouseY = 0;
6915       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
6916       {
6917          if(guiApp.driver)
6918             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
6919          if(this != guiApp.desktop)
6920          {
6921             mouseX -= absPosition.x + clientStart.x;
6922             mouseY -= absPosition.y + clientStart.y;
6923          }
6924       }
6925       if(x) *x = mouseX;
6926       if(y) *y = mouseY;
6927    }
6928
6929    DialogResult DoModal()
6930    {
6931       DialogResult returnCode = 0;
6932       int terminated = terminateX;
6933       isModal = true;
6934       incref this;
6935       while(!destroyed && guiApp.driver != null)
6936       {
6937          if(terminateX != terminated)
6938          {
6939             terminated = terminateX;
6940             guiApp.desktop.Destroy(0);
6941             if(guiApp.desktop.created)
6942             {
6943                terminated = 0;
6944                //printf("Resetting terminate X to 0\n");
6945                terminateX = 0;
6946             }
6947             break;
6948          }
6949
6950          guiApp.UpdateDisplay();
6951          if(!guiApp.ProcessInput(false))
6952             guiApp.Wait();
6953       }
6954       returnCode = this.returnCode;
6955       delete this;
6956       return returnCode;
6957    }
6958
6959    void DoModalStart()
6960    {
6961       isModal = true;
6962       incref this;
6963    }
6964
6965    bool DoModalLoop()
6966    {
6967       return !destroyed && guiApp.driver != null && terminateX < 2;
6968    }
6969
6970    DialogResult DoModalEnd()
6971    {
6972       DialogResult returnCode = this.returnCode;
6973       delete this;
6974       return returnCode;
6975    }
6976
6977    // --- Window manipulation ---
6978    /*bool GetDisabled()
6979    {
6980       bool disabled = this.disabled;
6981       Window window;
6982       for(window = this; (window = window.master); )
6983       {
6984          if(window.disabled)
6985          {
6986             disabled = true;
6987             break;
6988          }
6989       }
6990       return disabled;
6991    }*/
6992
6993    // --- Mouse Manipulation ---
6994    void GetNCMousePosition(int * x, int * y)
6995    {
6996       GetMousePosition(x, y);
6997       if(x) *x += clientStart.x;
6998       if(y) *y += clientStart.y;
6999    }
7000
7001    // --- Carets manipulation ---
7002    void GetCaretPosition(Point caretPos)
7003    {
7004       caretPos = this.caretPos;
7005    }
7006
7007    int GetCaretSize(void)
7008    {
7009       return caretSize;
7010    }
7011
7012    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7013    {
7014       Destroy(button.id);
7015       return true;
7016    }
7017
7018    bool CloseConfirmation(bool parentClosing)
7019    {
7020       bool result = true;
7021       OldLink slave;
7022       Window child;
7023
7024       if(closing)
7025          return false;
7026       if(terminateX > 1)
7027          return true;
7028          
7029       closing = true;
7030
7031       if(!OnClose(parentClosing))
7032          result = false;
7033
7034       // If you want to skip this, simply set modifiedDocument to false in OnClose
7035       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7036       {
7037          DialogResult dialogRes;
7038          char message[1024];
7039          if(fileName)
7040             sprintf(message, "Save changes to %s?", fileName);
7041          else
7042             sprintf(message, "Save changes to Untitled %d?", documentID);
7043
7044          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption, contents = message }.Modal();
7045
7046          if(dialogRes == yes)
7047          {
7048             // TOFIX: Precomp error if brackets are taken out
7049             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7050          }
7051          else if(dialogRes == cancel)
7052             result = false;
7053       }
7054
7055       if(result)
7056       {
7057          for(slave = slaves.first; slave; slave = slave.next)
7058             if(!((Window)slave.data).CloseConfirmation(true))
7059             {
7060                // ((Window)slave.data).CloseConfirmation(true);
7061                result = false;
7062                break;
7063             }
7064       }
7065
7066       if(result)
7067       {
7068          for(child = children.first; child; child = child.next)
7069             if(child.master != this && !child.CloseConfirmation(true))
7070             {
7071                result = false;
7072                break;
7073             }
7074       }
7075       closing = false;
7076       return result;
7077    }
7078
7079    // Static methods... move them somewhere else?
7080    void ::RestoreCaret()
7081    {
7082       if(guiApp.caretOwner)
7083          guiApp.caretOwner.UpdateCaret(false, false);
7084    }
7085
7086    void ::FreeMouseRange()
7087    {
7088       guiApp.interfaceDriver.SetMouseRange(null, null);
7089    }
7090
7091    // Menu Methods
7092    bool MenuFileClose(MenuItem selection, Modifiers mods)
7093    {
7094       Window document = activeChild;
7095       if(document)
7096          document.Destroy(0);
7097       return true;
7098    }
7099
7100    bool MenuFileExit(MenuItem selection, Modifiers mods)
7101    {
7102       Destroy(0);
7103       return true;
7104    }
7105
7106    bool MenuFileSave(MenuItem selection, Modifiers mods)
7107    {
7108       if(fileName)
7109       {
7110          fileMonitor.fileName = null;
7111          saving = true;
7112
7113          if(OnSaveFile(fileName))
7114          {
7115             //if(OnFileModified != Window::OnFileModified)
7116             {
7117                saving = false;
7118                fileMonitor.fileName = fileName;
7119             }
7120             return true;
7121          }
7122          else
7123          {
7124             MessageBox dialog { master = master, type = yesNoCancel, text = "Error writing file", contents = "Save as a different file?" };
7125             DialogResult answer = dialog.Modal();
7126             saving = false;
7127             if(answer != yes) return (bool)answer;
7128          }
7129       }
7130       return MenuFileSaveAs(selection, mods);
7131    }
7132
7133    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7134    {
7135       DialogResult result = (DialogResult)bool::true;
7136       FileDialog fileDialog = saveDialog;
7137
7138       if(!fileDialog)
7139          fileDialog = FileDialog {};
7140       if(fileDialog)
7141       {
7142          incref fileDialog;
7143          if(fileName)
7144             fileDialog.filePath = fileName;
7145          else
7146          {
7147             char filePath[MAX_FILENAME];
7148             sprintf(filePath, "Untitled %d", documentID);
7149             fileDialog.filePath = filePath;
7150          }
7151          fileMonitor.fileName = null;
7152
7153          fileDialog.type = save;
7154          fileDialog.text = "Save As";
7155
7156          while(true)
7157          {
7158             fileDialog.master = master.parent ? master : this;
7159             if(fileDialog.Modal() == ok)
7160             {
7161                char * filePath = fileDialog.filePath;
7162                saving = true;
7163                if(OnSaveFile(filePath))
7164                {
7165                   saving = false;
7166                   property::fileName = filePath;
7167                   NotifySaved(master, this, filePath);
7168                   break;
7169                }
7170                else
7171                {
7172                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = "Error writing file", contents = "Save as a different file?" };
7173                   DialogResult answer = dialog.Modal();
7174                   saving = false;
7175                   if(answer != yes) 
7176                   {
7177                      result = answer;
7178                      break;
7179                   }
7180                }
7181             }
7182             else
7183             {
7184                result = cancel;
7185                break;
7186             }
7187          }
7188          //if(OnFileModified != Window::OnFileModified && fileName)
7189          {
7190             if(fileName)
7191                fileMonitor.fileName = fileName;
7192          }
7193          delete fileDialog;
7194       }
7195       return (bool)result; // Actually returning result from Yes/NoCancel message box
7196    }
7197
7198    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7199    {
7200       Window document = activeChild;
7201       Window next;
7202       for(document = children.first; document; document = next)
7203       {
7204          next = document.next;
7205          if(document.style.isDocument || document.fileName)
7206             document.MenuFileSave(selection, mods);
7207       }
7208       return true;
7209    }
7210
7211    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7212    {
7213       Window document;
7214
7215       for(document = children.first; document; document = document.next)
7216          //if(document.style.isDocument && document.state == minimized)
7217          if(document.style.isActiveClient && document.state == minimized)
7218             document.SetState(minimized, false, mods);
7219       return true;
7220    }
7221
7222    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7223    {
7224       Window document = activeChild;
7225       if(document)
7226       {
7227          Window firstDocument = null;
7228          Window child;
7229          OldLink cycle = document.cycle.prev;
7230          int id = 0;
7231          while(true)
7232          {
7233             child = cycle.data;
7234             if(child.style.isActiveClient && !child.style.hidden)
7235             {
7236                Window last;
7237
7238                firstDocument = child;
7239                if(child.state == minimized)
7240                   child.SetState(minimized, false, mods);
7241                else
7242                {
7243                   child.positionID = id++;
7244                   child.SetState(normal, false, mods);
7245                   child.anchor.left.type = cascade;
7246                   {
7247                      int x, y, w, h;
7248                      child.normalSizeAnchor = *&child.sizeAnchor;
7249                      child.normalAnchor = child.anchor;
7250
7251                      // Break the anchors for moveable/resizable windows
7252                      if(child.style.fixed)
7253                      {
7254                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7255
7256                         (*&child.normalAnchor).left = x;
7257                         (*&child.normalAnchor).top = y;
7258                         (*&child.normalAnchor).right.type = none;
7259                         (*&child.normalAnchor).bottom.type = none;
7260
7261                         child.normalSizeAnchor.isClientW = false;
7262                         child.normalSizeAnchor.isClientH = false;
7263                         child.normalSizeAnchor.size.w = w;
7264                         child.normalSizeAnchor.size.h = h;
7265                         child.anchored = false;
7266                      }
7267
7268                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7269                      {
7270                         child.stateAnchor = child.normalAnchor;
7271                         child.stateSizeAnchor = child.normalSizeAnchor;
7272
7273                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7274                         child.Position(x, y, w, h, true, true, true, true, false, false);
7275                      }
7276                   }
7277                }
7278
7279                last = children.last;
7280                if(!child.style.stayOnTop)
7281                   for(; last && last.style.stayOnTop; last = last.prev);
7282                children.Move(child, last);
7283                childrenOrder.Move(child.order, childrenOrder.last);
7284             }
7285             if(cycle == document.cycle) break;
7286             cycle = cycle.prev;
7287          }
7288          if(firstDocument)
7289             firstDocument.Activate();
7290       }
7291       return true;
7292    }
7293
7294    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7295    {
7296       if(style.hasClose)
7297          Destroy(0);
7298       return true;
7299    }
7300
7301    // Close all closes all active clients, not all documents
7302    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7303    {
7304       Window next, document;
7305
7306       for(document = children.first; document; document = next)
7307       {
7308          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7309          if(document.style.isActiveClient)
7310             if(!document.Destroy(0) && !document.style.hidden)
7311                return false;
7312       }
7313       return true;
7314    }
7315
7316    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7317    {
7318       if(style.hasMaximize && state != maximized)
7319          SetState(maximized, 0, 0);
7320       return true;
7321    }
7322
7323    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7324    {
7325       if(style.hasMinimize && state != minimized)
7326       {
7327          SetState(minimized, 0, 0);
7328          parent.CycleChildren(false, true, false, true);
7329       }
7330       return true;
7331    }
7332
7333    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7334    {
7335       MenuMoveOrSize(false, selection ? true : false);
7336       return true;
7337    }
7338
7339    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7340    {
7341       CycleChildren(false, true, false, true);
7342       return true;
7343    }
7344
7345    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7346    {
7347       CycleChildren(true, true, false, true);
7348       return true;
7349    }
7350
7351    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7352    {
7353       MenuMoveOrSize(true, true);
7354       return true;
7355    }
7356
7357    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7358    {
7359       if(state != normal)
7360          SetState(normal, 0, 0);
7361       return true;
7362    }
7363
7364    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7365    {
7366       Window document;
7367       int id = selection.id;
7368       OldLink cycle = activeClient.cycle;
7369       int c = 0;
7370       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7371       while(true)
7372       {
7373          Window sibling = cycle.data;
7374          if(sibling.style.isActiveClient)
7375          {
7376             if(c == id)
7377                break;
7378             c++;
7379          }
7380          cycle = cycle.next;
7381       }
7382       document = cycle.data;
7383       document.Activate();
7384       
7385       //if(activeChild.state == maximized)
7386       //  document.SetState(maximized, false, mods);
7387       //else if(document.state == minimized)
7388       //   document.SetState(normal, false, mods);
7389       return true;
7390    }
7391
7392    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7393    {
7394       stayOnTop = !style.stayOnTop;
7395       return true;
7396    }
7397
7398    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7399    {
7400       Window document = activeChild;
7401       if(document)
7402       {
7403          Window firstDocument = null;
7404          OldLink cycle = document.cycle;
7405          int id = 0;
7406          while(true)
7407          {
7408             Window child = cycle.data;
7409             if(child.style.isActiveClient && !child.style.hidden)
7410             {
7411                if(!firstDocument) firstDocument = child;
7412                if(child.state == minimized)
7413                   child.SetState(minimized, false, mods);
7414                else
7415                {
7416                   child.positionID = id++;
7417                   child.SetState(normal, false, mods);
7418                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7419
7420                   child.anchor.left.type = hTiled;
7421                   {
7422                      int x, y, w, h;
7423                      child.normalSizeAnchor = *&child.sizeAnchor;
7424                      child.normalAnchor = child.anchor;
7425
7426                      // Break the anchors for moveable/resizable windows
7427                      if(child.style.fixed)
7428                      {
7429                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7430
7431                         (*&child.normalAnchor).left = x;
7432                         (*&child.normalAnchor).top = y;
7433                         (*&child.normalAnchor).right.type = none;
7434                         (*&child.normalAnchor).bottom.type = none;
7435                         child.normalSizeAnchor.isClientW = false;
7436                         child.normalSizeAnchor.isClientH = false;
7437                         child.normalSizeAnchor.size.w = w;
7438                         child.normalSizeAnchor.size.h = h;
7439                         child.anchored = false;
7440                      }
7441
7442                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7443                      {
7444                         child.stateAnchor = child.normalAnchor;
7445                         child.stateSizeAnchor = child.normalSizeAnchor;
7446
7447                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7448                         child.Position(x,y, w, h, true, true, true, true, false, true);
7449                      }
7450                   }
7451                }
7452             }
7453             if((cycle = cycle.next) == document.cycle) break;
7454          }
7455          if(firstDocument)
7456             firstDocument.Activate();
7457       }
7458       return true;
7459    }
7460
7461    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7462    {
7463       Window document = activeChild;
7464       if(document)
7465       {
7466          Window firstDocument = null;
7467          Window child;
7468          OldLink cycle = document.cycle;
7469          int id = 0;
7470          while(true)
7471          {
7472             child = cycle.data;
7473             //if(child.style.isDocument)
7474             if(child.style.isActiveClient && !child.style.hidden)
7475             {
7476                if(!firstDocument) firstDocument = child;
7477                if(child.state == minimized)
7478                   child.SetState(minimized, false, mods);
7479                else
7480                {
7481                   child.positionID = id++;
7482                   child.SetState(normal, false, mods);
7483                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7484
7485                   child.anchor.left.type = vTiled;
7486                   {
7487                      int x, y, w, h;
7488                      child.normalSizeAnchor = *&child.sizeAnchor;
7489                      child.normalAnchor = child.anchor;
7490
7491                      // Break the anchors for moveable/resizable windows
7492                      if(child.style.fixed)
7493                      {
7494                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7495
7496                         (*&child.normalAnchor).left = x;
7497                         (*&child.normalAnchor).top = y;
7498                         (*&child.normalAnchor).right.type = none;
7499                         (*&child.normalAnchor).bottom.type = none;
7500                         child.normalSizeAnchor.isClientW = false;
7501                         child.normalSizeAnchor.isClientH = false;
7502                         child.normalSizeAnchor.size.w = w;
7503                         child.normalSizeAnchor.size.h = h;
7504                         child.anchored = false;
7505                      }
7506
7507                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7508                      {
7509                         child.stateAnchor = child.normalAnchor;
7510                         child.stateSizeAnchor = child.normalSizeAnchor;
7511
7512                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7513                         child.Position(x,y, w, h, true, true, true, true, false, true);
7514                      }
7515                   }
7516                }
7517             }
7518             if((cycle = cycle.next) == document.cycle) break;
7519          }
7520          if(firstDocument)
7521             firstDocument.Activate();
7522       }
7523       return true;
7524    }
7525
7526    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7527    {
7528       WindowList dialog { master = this };
7529       Window document = (Window)dialog.Modal();
7530       if(document)
7531       {
7532          if(activeChild.state == maximized)
7533             document.SetState(maximized, false, mods);
7534          else if(document.state == minimized)
7535             document.SetState(normal, false, mods);
7536          document.Activate();
7537       }
7538       return true;
7539    }
7540
7541    // Virtual Methods
7542    virtual bool OnCreate(void);
7543    virtual void OnDestroy(void);
7544    virtual void OnDestroyed(void);
7545    virtual bool OnClose(bool parentClosing);
7546    virtual bool OnStateChange(WindowState state, Modifiers mods);
7547    virtual bool OnPostCreate(void);
7548    virtual bool OnMoving(int *x, int *y, int w, int h);
7549    virtual bool OnResizing(int *width, int *height);
7550    virtual void OnResize(int width, int height);
7551    virtual void OnPosition(int x, int y, int width, int height);
7552    virtual bool OnLoadGraphics(void);
7553    virtual void OnApplyGraphics(void);
7554    virtual void OnUnloadGraphics(void);
7555    virtual void OnRedraw(Surface surface);
7556    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7557    virtual void OnActivateClient(Window client, Window previous);
7558    virtual bool OnKeyDown(Key key, unichar ch);
7559    virtual bool OnKeyUp(Key key, unichar ch);
7560    virtual bool OnKeyHit(Key key, unichar ch);
7561    virtual bool OnSysKeyDown(Key key, unichar ch);
7562    virtual bool OnSysKeyUp(Key key, unichar ch);
7563    virtual bool OnSysKeyHit(Key key, unichar ch);
7564    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7565    virtual bool OnMouseLeave(Modifiers mods);
7566    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7567    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7568    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7569    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7570    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7571    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7572    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7573    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7574    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7575    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7576    virtual void OnMouseCaptureLost(void);
7577    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7578    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7579    virtual void OnDrawOverChildren(Surface surface);
7580    virtual bool OnFileModified(FileChange fileChange, char * param);
7581    virtual bool OnSaveFile(char * fileName);
7582
7583    // Skins Virtual Functions
7584    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7585    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7586    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7587    {
7588       *cw = *w;
7589       *ch = *h;      
7590    }
7591    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7592    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7593    virtual bool IsMouseMoving(int x, int y, int w, int h);
7594    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY);
7595    virtual void UpdateNonClient();
7596    virtual void SetBox(Box box);
7597    virtual bool IsInside(int x, int y)
7598    {
7599       return box.IsPointInside({x, y});
7600    }
7601    virtual bool IsOpaque()
7602    {
7603       return (!style.drawBehind || background.a == 255);
7604    }
7605
7606    // Notifications
7607    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7608    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7609    virtual void Window::NotifySaved(Window window, char * filePath);
7610
7611    // Public Methods
7612
7613    // Properties
7614    property Window parent
7615    {
7616       property_category "Layout"
7617       set
7618       {
7619          if(value || guiApp.desktop)
7620          {
7621             Window last;
7622             Window oldParent = parent;
7623             Anchor anchor = this.anchor;
7624
7625             if(value && value.IsDescendantOf(this)) return;
7626             if(value && value == this)
7627                return;
7628             if(!value) value = guiApp.desktop;
7629
7630             if(value == oldParent) return;
7631
7632             if(!master || (master == this.parent && master == guiApp.desktop))
7633                property::master = value;
7634             
7635             if(parent)
7636             {
7637                parent.children.Remove(this);
7638
7639                parent.Update(
7640                {
7641                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7642                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7643                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7644                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7645                });
7646             }
7647
7648             last = value.children.last;
7649
7650             if(style.isDocument)
7651             {
7652                if(parent)
7653                   parent.numDocuments--;
7654                documentID = value.GetDocumentID();
7655             }
7656
7657             if(style.isActiveClient && !style.hidden)
7658             {
7659                if(parent && parent != guiApp.desktop && !(style.hidden))
7660                {
7661                   if(state == minimized) parent.numIcons--;
7662                   parent.numPositions--;
7663                }
7664             }
7665
7666             if(!style.stayOnTop)
7667                for(; last && last.style.stayOnTop; last = last.prev);
7668
7669             value.children.Insert(last, this);
7670
7671             // *** NEW HERE: ***
7672             if(cycle)
7673                parent.childrenCycle.Delete(cycle);
7674             if(order)
7675                parent.childrenOrder.Delete(order);
7676             cycle = null;
7677             order = null;
7678
7679             //if(created)
7680             {
7681                if(created)
7682                {
7683                   int x = position.x, y = position.y, w = size.w, h = size.h;
7684                   
7685                   int vpw, vph;
7686
7687                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7688                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7689                   
7690                   vpw = value.clientSize.w;
7691                   vph = value.clientSize.h;
7692                   if(style.nonClient)
7693                   {
7694                      vpw = value.size.w;
7695                      vph = value.size.h;
7696                   }
7697                   else if(style.fixed)
7698                   {
7699                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7700                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7701                   }
7702
7703                   anchor = this.anchor;
7704
7705                   if(anchor.left.type == offset)            anchor.left.distance = x;
7706                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7707                   if(anchor.top.type == offset)             anchor.top.distance = y;
7708                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7709                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7710                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7711                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7712                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7713                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7714                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7715
7716                   if(!anchor.left.type && !anchor.right.type)
7717                   {
7718                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7719                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7720                   }
7721                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7722                   if(!anchor.top.type && !anchor.bottom.type)
7723                   {
7724                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7725                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7726                   }
7727                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7728                }
7729                parent = value;
7730
7731                // *** NEW HERE ***
7732                if(!style.inactive)
7733                {
7734                   if(!style.noCycle)
7735                      parent.childrenCycle.Insert(
7736                         (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
7737                         cycle = OldLink { data = this });
7738                   parent.childrenOrder.Insert(
7739                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
7740                      order = OldLink { data = this });
7741                }
7742
7743                if(!style.hidden && style.isActiveClient)
7744                {
7745                   positionID = parent.GetPositionID(this);
7746                   parent.numPositions++;
7747                   if(state == minimized) parent.numIcons--;
7748                }
7749
7750                // *** FONT INHERITANCE ***
7751                if(!setFont && oldParent) 
7752                   stopwatching(oldParent, font);
7753
7754                if(systemFont)
7755                {
7756                   RemoveResource(systemFont);
7757                   delete systemFont;
7758                }
7759                // TESTING WITH WATCHERS:
7760                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7761                // usedFont = setFont ? setFont : (systemFont);
7762
7763                if(!usedFont)
7764                {
7765                   if(guiApp.currentSkin)
7766                   {
7767                      systemFont = guiApp.currentSkin.SystemFont();
7768                      incref systemFont;
7769                   }
7770                   usedFont = systemFont;
7771                   AddResource(systemFont);
7772                }
7773
7774                if(!setFont)
7775                   watch(value)
7776                   {
7777                      font
7778                      {
7779                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7780                         firewatchers font;
7781                         Update(null);
7782                      }
7783                   };
7784                
7785                firewatchers font;
7786
7787
7788                if(value.rootWindow && value.rootWindow.display && rootWindow)
7789                {
7790                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
7791                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
7792                   
7793                   if(reloadGraphics)
7794                      UnloadGraphics(false);
7795                   SetupDisplay();
7796                   if(reloadGraphics)
7797                      LoadGraphics(false, false);
7798                      
7799                   /*
7800                   if(value.rootWindow != rootWindow)
7801                      DisplayModeChanged();
7802                   else
7803                   */
7804                }
7805                scrolledPos.x = MININT; // Prevent parent update
7806                property::anchor = anchor;
7807                /*
7808                {
7809                   int x, y, w, h;
7810                   if(guiApp.currentSkin)
7811                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
7812
7813                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7814                   Position(x, y, w, h, true, true, true, true, false, true);
7815                }
7816                */
7817
7818             }
7819             // else parent = value;
7820          }
7821       }
7822       get { return parent; }
7823    };
7824
7825    property Window master
7826    {
7827       property_category "Behavior"
7828       set
7829       {
7830          //if(this == value) return;
7831          if(value && value.IsSlaveOf(this)) return;
7832
7833          if(master != value)
7834          {
7835             if(master)
7836             {
7837                OldLink slaveHolder;
7838                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
7839                   if(slaveHolder.data == this)
7840                   {
7841                      master.slaves.Delete(slaveHolder);
7842                      break;
7843                   }
7844             }
7845
7846             if(value)
7847             {
7848                value.slaves.Add(OldLink { data = this });
7849
7850                if(hotKey)
7851                {
7852                   if(master)
7853                      master.hotKeys.Remove(hotKey);
7854                   value.hotKeys.Add(hotKey);
7855                   hotKey = null;
7856                }
7857                if(master && master.defaultControl == this)
7858                   master.defaultControl = null;
7859
7860                if(style.isDefault && !value.defaultControl)
7861                   value.defaultControl = this;
7862
7863             }
7864          }
7865          master = value;
7866       }
7867       get { return master ? master : parent; }
7868    };
7869
7870    property char * text
7871    {
7872       property_category "Appearance"
7873       watchable
7874       set
7875       {
7876          delete caption;
7877          if(value)
7878          {
7879             caption = new char[strlen(value)+1];
7880             if(caption)
7881                strcpy(caption, value);
7882          }
7883          if(created)
7884             UpdateCaption();
7885       }
7886       get { return caption; }
7887    };
7888
7889    property Key hotKey
7890    {
7891       property_category "Behavior"
7892       set
7893       {
7894          setHotKey = value;
7895          if(created)
7896          {
7897             if(value)
7898             {
7899                if(!hotKey)
7900                   master.hotKeys.Add(hotKey = HotKeySlot { });
7901                if(hotKey)
7902                {
7903                   hotKey.key = value;
7904                   hotKey.window = this;
7905                }
7906             }
7907             else if(hotKey)
7908             {
7909                master.hotKeys.Delete(hotKey);
7910                hotKey = null;
7911             }
7912          }
7913       }
7914       get { return hotKey ? hotKey.key : 0; }
7915    };
7916
7917    property Color background
7918    {
7919       property_category "Appearance"
7920       set
7921       {
7922          background.color = value;
7923          firewatchers;
7924          if(created)
7925          {
7926             Update(null);
7927             if(this == rootWindow)
7928                guiApp.interfaceDriver.SetRootWindowColor(this);
7929          }
7930       }
7931       get { return background.color; }
7932    };
7933
7934    property Percentage opacity
7935    {
7936       property_category "Appearance"
7937       set
7938       {
7939          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
7940          drawBehind = background.a ? false : true;
7941       }
7942       get { return background.a / 255.0f; }
7943    };
7944
7945    property Color foreground
7946    {
7947       property_category "Appearance"
7948       set
7949       {
7950          foreground = value;
7951          firewatchers;
7952          if(created)
7953             Update(null);
7954       }
7955       get { return foreground; }
7956    };
7957
7958    property BorderStyle borderStyle
7959    {
7960       property_category "Appearance"
7961       set
7962       {
7963          if(!((BorderBits)value).fixed)
7964          {
7965             style.hasClose = false;
7966             style.hasMaximize = false;
7967             style.hasMinimize = false;
7968          }
7969          style.borderBits = value;
7970          if(created)
7971          {
7972             int x, y, w, h;
7973             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
7974
7975             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7976             Position(x, y, w, h, true, true, true, true, false, true);
7977             CreateSystemChildren();
7978          }
7979       }
7980       get { return (BorderStyle)style.borderBits; } 
7981    };
7982
7983    property Size minClientSize
7984    {
7985       property_category "Layout"
7986       set { minSize = value; }
7987       get { value = minSize; }
7988    };
7989
7990    property Size maxClientSize
7991    {
7992       property_category "Layout"
7993       set { maxSize = value; }
7994       get { value = maxSize; }
7995    };
7996
7997    property bool hasMaximize
7998    {
7999       property_category "Window Style"
8000       set
8001       {
8002          style.hasMaximize = value;
8003          if(value) { style.fixed = true; style.contour = true; }
8004          if(created)
8005          {
8006             int x, y, w, h;
8007             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8008
8009             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8010             Position(x, y, w, h, true, true, true, true, false, true);
8011
8012             CreateSystemChildren();
8013          }
8014       }
8015       get { return style.hasMaximize; }
8016    };
8017
8018    property bool hasMinimize
8019    {
8020       property_category "Window Style"
8021       set
8022       {
8023          style.hasMinimize = value;
8024          if(value) { style.fixed = true; style.contour = true; }
8025          if(created)
8026          {
8027             int x, y, w, h;
8028             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8029
8030             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8031             Position(x, y, w, h, true, true, true, true, false, true);
8032
8033             CreateSystemChildren();
8034          }
8035       }
8036       get { return style.hasMinimize;  }
8037    };
8038
8039    property bool hasClose
8040    {
8041       property_category "Window Style"
8042       set
8043       {
8044          style.hasClose = value;
8045          if(value) { style.fixed = true; style.contour = true; }
8046          if(created)
8047          {
8048             int x, y, w, h;
8049             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8050             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8051             Position(x, y, w, h, true, true, true, true, false, true);
8052             CreateSystemChildren();
8053          }
8054       }
8055       get { return style.hasClose; }
8056    };
8057    
8058    property bool nonClient
8059    {
8060       property_category "Layout"
8061       set
8062       {
8063          style.nonClient = value;
8064          if(value)
8065             style.stayOnTop = true;
8066       }
8067       get { return style.nonClient; }
8068    };
8069
8070    property bool inactive
8071    {
8072       property_category "Behavior"
8073       set
8074       {
8075          if(value) 
8076          {
8077             // *** NEW HERE: ***
8078             if(!style.inactive)
8079             {
8080                if(cycle)
8081                   parent.childrenCycle.Delete(cycle);
8082                if(order)
8083                   parent.childrenOrder.Delete(order);
8084                cycle = null;
8085                order = null;
8086             }
8087
8088             if(created)
8089             {
8090                active = false; // true;
8091                if(parent.activeChild == this)
8092                   parent.activeChild = null;
8093                if(parent.activeClient == this)
8094                   parent.activeClient = null;
8095             }
8096          }
8097          else
8098          {
8099             if(style.inactive)
8100             {
8101                if(!style.noCycle)
8102                {
8103                   parent.childrenCycle.Insert(
8104                      (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
8105                      cycle = OldLink { data = this });
8106                }
8107                parent.childrenOrder.Insert(
8108                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8109                   order = OldLink { data = this });
8110             }
8111          }
8112          style.inactive = value;
8113       }
8114       get { return style.inactive; }
8115    };
8116
8117    property bool clickThrough
8118    {
8119       property_category "Behavior"
8120       set { style.clickThrough = value; }
8121       get { return style.clickThrough; }
8122    };
8123
8124    property bool isRemote
8125    {
8126       property_category "Behavior"
8127       set { style.isRemote = value; }
8128       get { return style.isRemote; }
8129    };
8130
8131    property bool noCycle
8132    {
8133       property_category "Behavior"
8134       set { style.noCycle = value; }
8135       get { return style.noCycle; }
8136    };
8137
8138    property bool isModal
8139    {
8140       property_category "Behavior"
8141       set { style.modal = value; }
8142       get { return style.modal; }
8143    };
8144
8145    property bool interim
8146    {
8147       property_category "Behavior"
8148       set { style.interim = value; }
8149       get { return style.interim; }
8150    };
8151
8152    property bool tabCycle
8153    {
8154       property_category "Behavior"
8155       set { style.tabCycle = value; }
8156       get { return style.tabCycle; }
8157    };
8158      
8159    property bool isDefault
8160    {
8161       property_category "Behavior"
8162       set
8163       {
8164          if(master)
8165          {
8166             if(value)
8167             {
8168                Window sibling;
8169                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8170                   if(sibling != this && sibling.style.isDefault)
8171                      sibling.style.isDefault = false;*/
8172                if(master.defaultControl)
8173                   master.defaultControl.style.isDefault = false;
8174                master.defaultControl = this;
8175             }
8176             else if(master.defaultControl == this)
8177                master.defaultControl = null;
8178
8179             // Update(null);
8180          }
8181          style.isDefault = value;
8182          if(created)
8183             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8184       }
8185       get { return style.isDefault; }
8186    };
8187
8188    property bool drawBehind
8189    {
8190       property_category "Window Style"
8191       set { style.drawBehind = value; }
8192       get { return style.drawBehind; }
8193    };
8194
8195    property bool hasMenuBar
8196    {
8197       property_category "Window Style"
8198       set
8199       {
8200          if(value) 
8201          {
8202             if(!menu)
8203             {
8204                menu = Menu { };
8205                incref menu;
8206             }
8207             if(created && !menuBar)
8208             {
8209                menuBar =
8210                   PopupMenu 
8211                   {
8212                      this, menu = menu,
8213                      isMenuBar = true,
8214                      anchor = Anchor { top = 23, left = 1, right = 1 },
8215                      size.h = 24,
8216                      inactive = true, nonClient = true                            
8217                   };
8218                menuBar.Create();
8219             }
8220          }
8221          else if(created && menuBar)
8222          {
8223             menuBar.Destroy(0);
8224             menuBar = null;
8225          }
8226          style.hasMenuBar = value;
8227       }
8228       get { return style.hasMenuBar; }
8229    };
8230
8231    property bool hasStatusBar
8232    {
8233       property_category "Window Style"
8234       set
8235       {
8236          if(value)
8237          {
8238             if(!statusBar)
8239             {
8240                statusBar = StatusBar { this };
8241                incref statusBar;
8242                if(created)
8243                   statusBar.Create();
8244             }
8245          }
8246          else if(statusBar)
8247             delete statusBar;
8248          style.hasStatusBar = value;
8249       }
8250       get { return style.hasStatusBar; }
8251    };
8252    property bool stayOnTop
8253    {
8254       property_category "Window Style"
8255       set
8256       {
8257          if(value)
8258          {
8259             if(created && !style.stayOnTop)
8260             {
8261                if(rootWindow == this)
8262                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8263                else if(parent.children.last != this)
8264                {
8265                   parent.children.Move(this, parent.children.last);
8266                   Update(null);
8267                }
8268             }
8269             style.stayOnTop = true;
8270          }
8271          else
8272          {
8273             if(created && style.stayOnTop)
8274             {
8275                if(rootWindow == this)
8276                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8277                else
8278                {
8279                   Window last;
8280                   if(order)
8281                   {
8282                      OldLink order;
8283                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
8284                          order && ((Window)order.data).style.stayOnTop;
8285                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8286                       last = order ? order.data : null;
8287                   }
8288                   else
8289                   {
8290                      for(last = parent.children.last; 
8291                          last && last.style.stayOnTop;
8292                          last = last.prev);
8293                   }
8294
8295                   parent.children.Move(this, last);
8296                   Update(null);
8297                }
8298             }
8299             style.stayOnTop = false;
8300          }
8301       }
8302       get { return style.stayOnTop; }
8303    };
8304
8305    property Menu menu
8306    {
8307       property_category "Window Style"
8308       set
8309       {
8310          delete menu;
8311          if(value)
8312          {
8313             menu = value;
8314             incref menu;
8315          }
8316
8317          if(menuBar && !value)
8318          {
8319             menuBar.Destroy(0);
8320             menuBar = null;
8321          }
8322          if(created)
8323          {
8324             if(!menuBar && style.hasMenuBar && value)
8325             {
8326                menuBar = PopupMenu
8327                          { 
8328                             this, menu = value, isMenuBar = true, 
8329                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
8330                             inactive = true, nonClient = true
8331                          };
8332                 menuBar.Create();
8333             }
8334             UpdateActiveDocument(null);
8335          }
8336       }
8337       get { return menu; }
8338    };
8339
8340    property FontResource font
8341    {
8342       property_category "Appearance"
8343       watchable
8344       isset { return setFont ? true : false; }
8345       set
8346       {
8347          if(this)
8348          {
8349             if(value && !setFont) { stopwatching(parent, font); }
8350             else if(!value && setFont)
8351             {
8352                watch(parent)
8353                {
8354                   font
8355                   {
8356                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8357                      firewatchers font;
8358                      Update(null);
8359                   }
8360                };
8361             }
8362
8363             if(setFont)
8364             {
8365                RemoveResource(setFont);
8366                delete setFont;
8367             }
8368             if(systemFont)
8369             {
8370                RemoveResource(systemFont);
8371                delete systemFont;
8372             }
8373             setFont = value;
8374             if(setFont)
8375             {
8376                incref setFont;
8377                AddResource(setFont);
8378             }
8379
8380             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8381             if(!usedFont)
8382             {
8383                systemFont = guiApp.currentSkin.SystemFont();
8384                incref systemFont;
8385                usedFont = systemFont;
8386                AddResource(systemFont);
8387             }
8388
8389             firewatchers;
8390
8391             Update(null);
8392          }
8393       }
8394       get { return usedFont; }
8395    };
8396
8397    property SizeAnchor sizeAnchor
8398    {
8399       property_category "Layout"
8400       isset
8401       {
8402          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8403                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8404             sizeAnchor.isClientW != sizeAnchor.isClientH;
8405       }
8406       set
8407       {
8408          int x, y, w, h;
8409          sizeAnchor = value;
8410
8411          normalSizeAnchor = sizeAnchor;
8412
8413          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8414          {
8415             stateAnchor = normalAnchor;
8416             stateSizeAnchor = normalSizeAnchor;
8417
8418             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8419             Position(x,y, w, h, true, true, true, true, false, true);
8420          }
8421       }
8422       get
8423       {
8424          value =
8425          {
8426             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8427             sizeAnchor.isClientW,
8428             sizeAnchor.isClientH
8429          };
8430       }
8431    };
8432
8433    property Size size
8434    {
8435       property_category "Layout"
8436       isset
8437       {
8438          Anchor thisAnchor = anchor;
8439          SizeAnchor thisSizeAnchor = sizeAnchor;
8440          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8441          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8442          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8443          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8444                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8445             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8446       }
8447       set
8448       {
8449          int x, y, w, h;
8450
8451          sizeAnchor.isClientW = false;
8452          sizeAnchor.isClientH = false;
8453          sizeAnchor.size = value;
8454
8455          normalSizeAnchor = sizeAnchor;
8456
8457          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8458          {
8459             stateAnchor = normalAnchor;
8460             stateSizeAnchor = normalSizeAnchor;
8461
8462             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8463             Position(x, y, w, h, true, true, true, true, false, true);
8464          }
8465       }
8466       get { value = size; }
8467    };
8468
8469    property Size clientSize
8470    {
8471       property_category "Layout"
8472       isset
8473       {
8474          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8475                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8476             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8477       }
8478       set
8479       {
8480          int x, y, w, h;
8481          sizeAnchor.isClientW = true;
8482          sizeAnchor.isClientH = true;
8483          sizeAnchor.size = value;
8484
8485          normalSizeAnchor = sizeAnchor;
8486
8487          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8488          {
8489             stateAnchor = normalAnchor;
8490             stateSizeAnchor = normalSizeAnchor;
8491
8492             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8493             Position(x,y, w, h, true, true, true, true, false, true);
8494          }
8495       }
8496       get { value = clientSize; }
8497    };
8498
8499    property Size initSize { get { value = sizeAnchor.size; } };
8500
8501    property Anchor anchor
8502    {
8503       property_category "Layout"
8504       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8505
8506       set
8507       {
8508          if(value != null)
8509          {
8510             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8511             {
8512                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8513                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8514             }
8515             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8516             {
8517                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8518                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8519             }
8520             anchor = value;
8521
8522             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
8523             {
8524                anchor.left.distance = 0;
8525                anchor.horz.type = 0;
8526             }
8527             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8528             {
8529                anchor.top.distance = 0;
8530                anchor.vert.type = 0;
8531             }
8532
8533             anchored = true;
8534
8535             //if(created)
8536             {
8537                int x, y, w, h;
8538
8539                normalAnchor = anchor;
8540                
8541                // Break the anchors for moveable/resizable windows
8542                /*if(style.fixed ) //&& value.left.type == cascade)
8543                {
8544                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8545
8546                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8547                   normalSizeAnchor = SizeAnchor { { w, h } };
8548                   anchored = false;
8549                }*/
8550                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8551                {
8552                   stateAnchor = normalAnchor;
8553                   stateSizeAnchor = normalSizeAnchor;
8554
8555                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8556                   Position(x, y, w, h, true, true, true, true, false, true);
8557                }
8558             }
8559          }
8560          else
8561          {
8562             anchored = false;
8563          }
8564       }
8565       get { value = this ? anchor : Anchor { }; }
8566    };
8567
8568    property Point position
8569    {
8570       property_category "Layout"
8571       set
8572       {
8573          if(value == null) return;
8574
8575          anchor.left = value.x;
8576          anchor.top  = value.y;
8577          anchor.right.type = none;
8578          anchor.bottom.type = none;
8579          //if(created)
8580          {
8581             int x, y, w, h;
8582
8583             normalAnchor = anchor;
8584
8585             // Break the anchors for moveable/resizable windows
8586             /*
8587             if(style.fixed)
8588             {
8589                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8590
8591                normalAnchor.left = x;
8592                normalAnchor.top = y;
8593                normalAnchor.right.type = none;
8594                normalAnchor.bottom.type = none;
8595                normalSizeAnchor.size.width = w;
8596                normalSizeAnchor.size.height = h;
8597                anchored = false;
8598             }
8599             */
8600             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8601             {
8602                stateAnchor = normalAnchor;
8603                stateSizeAnchor = normalSizeAnchor;
8604
8605                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8606                Position(x,y, w, h, true, true, true, true, false, true);
8607             }
8608          }
8609       }
8610       get { value = position; }
8611    };
8612
8613    property bool disabled
8614    {
8615       property_category "Behavior"
8616       set
8617       {
8618          if(this && disabled != value)
8619          {
8620             disabled = value;
8621             if(created)
8622                Update(null);
8623          }
8624       }
8625       get { return (bool)disabled; }
8626    };
8627
8628    property bool isEnabled
8629    {
8630       get
8631       {
8632          Window parent;
8633          for(parent = this; parent; parent = parent.parent)
8634             if(parent.disabled)
8635                return false;
8636          return true;
8637       }
8638    };
8639
8640    property WindowState state
8641    {
8642       property_category "Behavior"
8643       set { SetState(value, false, 0); }
8644       get { return this ? state : 0; }
8645    };
8646
8647    property bool visible
8648    {
8649       property_category "Behavior"
8650       set
8651       {
8652          if(this && !value && !style.hidden && parent)
8653          {
8654             bool wasActiveChild = parent.activeChild == this;
8655             Window client = null;
8656
8657             style.hidden = true;
8658             if(style.isActiveClient)
8659             {
8660                parent.numPositions--;
8661                if(state == minimized) parent.numIcons--;
8662             }
8663
8664             if(created)
8665             {
8666                OldLink prevOrder = null;
8667
8668                if(rootWindow == this)
8669                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8670                else
8671                {
8672                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8673                   if(style.nonClient)
8674                   {
8675                      box.left   -= parent.clientStart.x;
8676                      box.top    -= parent.clientStart.y;
8677                      box.right  -= parent.clientStart.x;
8678                      box.bottom -= parent.clientStart.y;
8679                   }
8680                   parent.Update(box);
8681                }
8682                if(style.modal && master && master.modalSlave == this)
8683                   master.modalSlave = null;
8684
8685                if(order)
8686                {
8687                   OldLink tmpPrev = order.prev;
8688                   client = tmpPrev ? tmpPrev.data : null;
8689                   if(client && !client.style.hidden && !client.destroyed && client.created)
8690                      prevOrder = tmpPrev;
8691                   for(;;)
8692                   {
8693                      client = tmpPrev ? tmpPrev.data : null;
8694                      if(client == this) { client = null; break; }
8695                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8696                      {
8697                         tmpPrev = client.order.prev;
8698                      }
8699                      else
8700                      {
8701                         if(client)
8702                            prevOrder = tmpPrev;
8703                         break;
8704                      }
8705                   }
8706
8707                   // If this window can be an active client, make sure the next window we activate can also be one
8708                   if(!style.nonClient && style.isActiveClient)
8709                   {
8710                      tmpPrev = prevOrder;
8711                      for(;;)
8712                      {
8713                         client = tmpPrev ? tmpPrev.data : null;
8714                         if(client == this) { client = null; break; }
8715                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8716                         {
8717                            tmpPrev = client.order.prev;
8718                         }
8719                         else 
8720                         {
8721                            if(client)
8722                               prevOrder = tmpPrev;
8723                            break;
8724                         }
8725                      }
8726                      if(client && client.style.hidden) client = null;
8727                   }
8728                }
8729
8730                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
8731                {
8732                   if(order && prevOrder && prevOrder.data != this)
8733                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8734                   else
8735                      ActivateEx(false, false, false, true, null, null);
8736
8737                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8738                   if(parent.activeClient == this)
8739                   {
8740                      parent.activeClient = null;
8741                      parent.UpdateActiveDocument(null);
8742                   }
8743                }
8744                else if(parent.activeClient == this)
8745                {
8746                   parent.activeClient = client;
8747                   parent.UpdateActiveDocument(this);
8748                }
8749
8750                // *** Not doing this anymore ***
8751               /*
8752                if(cycle)
8753                   parent.childrenCycle.Delete(cycle);
8754                if(order)
8755                   parent.childrenOrder.Delete(order);
8756                cycle = null;
8757                order = null;
8758                */
8759                
8760                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8761             }
8762
8763             firewatchers;
8764          }
8765          else if(this && value && style.hidden)
8766          {
8767             style.hidden = false;
8768             if(created)
8769             {
8770                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8771                if(rootWindow == this)
8772                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
8773
8774                if(style.modal && master)
8775                   master.modalSlave = this;
8776
8777                if(style.isActiveClient)
8778                {
8779                   positionID = parent.GetPositionID(this);
8780                   parent.numPositions++;
8781                   if(state == minimized) parent.numIcons++;
8782                }
8783
8784                // *** NOT DOING THIS ANYMORE ***
8785                /*
8786                if(!(style.inactive))
8787                {
8788                   if(!(style.noCycle))
8789                   {
8790                      cycle = parent.childrenCycle.AddAfter(
8791                         (parent.activeChild && parent.activeChild.cycle) ? 
8792                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
8793                      cycle.data = this;
8794                   }
8795                   order = parent.childrenOrder.AddAfter(
8796                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8797                      sizeof(OldLink));
8798                   order.data = this;
8799                }
8800                */
8801      
8802                /*
8803                if(true || !parent.activeChild)
8804                   ActivateEx(true, false, true, true, null, null);
8805                */
8806                if(creationActivation == activate)
8807                   ActivateEx(true, false, true, true, null, null);
8808                else if(creationActivation == flash && !object)
8809                   Flash();               
8810
8811                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8812                Update(null);
8813
8814                // rootWindow.
8815                ConsequentialMouseMove(false);
8816             }
8817
8818             firewatchers;
8819          }
8820       }
8821
8822       get { return (style.hidden || !setVisible) ? false : true; }
8823    };
8824     
8825    property bool isDocument
8826    {
8827       property_category "Document"
8828       set { style.isDocument = value; }
8829       get { return style.isDocument; }
8830    };
8831
8832    property bool mergeMenus
8833    {
8834       property_category "Window Style"
8835       set { mergeMenus = value; }
8836       get { return (bool)mergeMenus; }
8837    };
8838
8839    property bool hasHorzScroll
8840    {
8841       property_category "Window Style"
8842       set
8843       {
8844          if(value)
8845          {
8846             if(!style.hasHorzScroll && created)
8847             {
8848                CreateSystemChildren();         
8849                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8850             }
8851          }
8852          else if(style.hasHorzScroll)
8853          {
8854             sbh.Destroy(0);
8855             sbh = null;
8856             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8857          }
8858          style.hasHorzScroll = value;
8859       }
8860
8861       get { return style.hasHorzScroll; }
8862    };
8863
8864    property bool hasVertScroll
8865    {
8866       property_category "Window Style"
8867       set
8868       {
8869          if(value)
8870          {
8871             if(!style.hasVertScroll && created)
8872             {
8873                style.hasVertScroll = true;
8874                CreateSystemChildren();
8875                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8876             }
8877          }
8878          else if(style.hasVertScroll)
8879          {
8880             sbv.Destroy(0);
8881             sbv = null;
8882             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8883          }
8884          style.hasVertScroll = value;
8885       }
8886       get { return style.hasVertScroll; }
8887    };
8888
8889    property bool dontHideScroll
8890    {
8891       property_category "Behavior"
8892       set
8893       {
8894          scrollFlags.dontHide = value;
8895          if(value)
8896          {
8897             //UpdateScrollBars(true, true);
8898             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
8899          }
8900          else
8901          {
8902             // UpdateScrollBars(true, true);
8903             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
8904          }
8905       }
8906       get { return scrollFlags.dontHide; }
8907    };
8908
8909    property bool dontScrollVert
8910    {
8911       property_category "Behavior"
8912       set { style.dontScrollVert = value; }
8913       get { return style.dontScrollVert; }
8914    };
8915    property bool dontScrollHorz
8916    {
8917       property_category "Behavior"
8918       set { style.dontScrollHorz = value; }
8919       get { return style.dontScrollHorz; }
8920    };
8921
8922    property bool snapVertScroll
8923    {
8924       property_category "Behavior"
8925       set
8926       {
8927          scrollFlags.snapY = value;
8928          if(sbv) sbv.snap = value;
8929       }
8930       get { return scrollFlags.snapY; }
8931    };
8932    property bool snapHorzScroll
8933    {
8934        property_category "Behavior"
8935       set
8936       {
8937          scrollFlags.snapX = value;
8938          if(sbh) sbh.snap = value;
8939       }
8940       get { return scrollFlags.snapX; }
8941    };
8942
8943    property Point scroll
8944    {
8945       property_category "Behavior"
8946       set
8947       {
8948          // scroll = value;
8949          // TESTING THIS IMPLEMENTATION:
8950          SetScrollPosition(value.x, value.y);
8951       }
8952       get { value = scroll; }
8953    };
8954
8955    property bool modifyVirtualArea
8956    {
8957       property_category "Behavior"
8958       set { modifyVirtArea = value; }
8959       get { return (bool)modifyVirtArea; }
8960    };
8961
8962    property char * fileName
8963    {
8964       property_category "Document"
8965       set
8966       {
8967          if(menu && ((!fileName && value) || (fileName && !value)))
8968          {
8969             MenuItem item = menu.FindItem(MenuFileSave, 0);
8970             if(item) item.disabled = !modifiedDocument && value;
8971          }
8972
8973          delete fileName;
8974
8975          if(value && value[0])
8976             fileName = CopyString(value);
8977
8978          if(parent && this == parent.activeClient)
8979             parent.UpdateActiveDocument(null);
8980          else
8981             UpdateCaption();
8982
8983          // if(style.isDocument)
8984          if(!saving)
8985             fileMonitor.fileName = value;
8986       }
8987       get { return fileName; }
8988    };
8989
8990    property int id
8991    {
8992       property_category "Data"
8993       set { id = value; }
8994       get { return id; }
8995    };
8996
8997    property bool modifiedDocument
8998    {
8999       property_category "Document"
9000       set
9001       {
9002          if(style.isDocument || fileName)
9003          {
9004             if(menu)
9005             {
9006                MenuItem item = menu.FindItem(MenuFileSave, 0);
9007                if(item) item.disabled = !value && fileName;
9008             }
9009          }
9010
9011          if(modifiedDocument != value)
9012          {
9013             modifiedDocument = value;
9014             if(style.isDocument || fileName)
9015                UpdateCaption();
9016          }
9017       }
9018       get { return (bool)modifiedDocument; }
9019    };
9020
9021    property bool showInTaskBar
9022    {
9023       property_category "Window Style"
9024       set { style.showInTaskBar = value; }
9025       get { return (style.showInTaskBar; }
9026    };
9027    property FileDialog saveDialog { set { saveDialog = value; } };
9028    property bool isActiveClient
9029    {
9030       property_category "Behavior"
9031       set { style.isActiveClient = value; }
9032       get { return style.isActiveClient; }
9033    };
9034
9035    property Cursor cursor
9036    {
9037       property_category "Appearance"
9038       set
9039       {
9040          cursor = value;
9041          SelectMouseCursor();
9042       }
9043       get { return cursor; }
9044    };      
9045
9046 //#if !defined(ECERE_VANILLA)
9047    property char * name
9048    {
9049       property_category "Design"
9050       get
9051       {
9052          return (this && object) ? object.name : null;
9053       }
9054       set
9055       {
9056          if(activeDesigner)
9057             activeDesigner.RenameObject(object, value);
9058       }
9059    };
9060 //#endif
9061    property char * displayDriver
9062    {
9063       property_category "Behavior"
9064       set
9065       {
9066          dispDriver = GetDisplayDriver(value);
9067          //DisplayModeChanged();
9068       }
9069       get
9070       {
9071          return dispDriver ? dispDriver.name : null;
9072       }
9073    }
9074
9075    // RUNTIME PROPERTIES
9076    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9077    property Size scrollArea
9078    {
9079       property_category "Behavior"
9080       set
9081       {
9082          if(value != null)
9083             SetScrollArea(value.w, value.h, false);
9084          else
9085             SetScrollArea(0,0, true);
9086       }
9087       get { value = scrollArea; }
9088       isset
9089       {
9090          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9091       }
9092    };
9093    property bool is3D
9094    {
9095       property_category "Layout"
9096       set { if(this) is3D = value; }
9097       get { return (bool)is3D; }
9098    };
9099
9100    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9101                                                                                                             
9102    // Will be merged with font later
9103    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9104    property Point clientStart { get { value = clientStart; } };
9105    property Point absPosition { get { value = absPosition; } };
9106    property Anchor normalAnchor { get {value = normalAnchor; } };
9107    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9108    property bool active { get { return (bool)active; } };
9109    property bool created { get { return (bool)created; } };
9110    property bool destroyed { get { return (bool)destroyed; } };
9111    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9112    property Window firstChild { get { return children.first; } };   
9113    property Window lastChild { get { return children.last; } };   
9114    property Window activeClient { get { return activeClient; } };
9115    property Window activeChild { get { return activeChild; } };
9116    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9117    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9118    property ScrollBar horzScroll { get { return sbh; } };
9119    property ScrollBar vertScroll { get { return sbv; } };
9120    property StatusBar statusBar { get { return statusBar; } };
9121    property Window rootWindow { get { return rootWindow; } };   
9122    property bool closing { get { return (bool)closing; } set { closing = value; } };
9123    property int documentID { get { return documentID; } };
9124    property Window previous { get { return prev; } }
9125    property Window next { get { return next; } }
9126    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9127    property PopupMenu menuBar { get { return menuBar; } }
9128    property ScrollBar sbv { get { return sbv; } }
9129    property ScrollBar sbh { get { return sbh; } }
9130    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9131    property void * systemHandle { get { return windowHandle; } }
9132    property Button minimizeButton { get { return sysButtons[0]; } };
9133    property Button maximizeButton { get { return sysButtons[1]; } };   
9134    property Button closeButton { get { return sysButtons[2]; } };
9135    property BitmapResource icon
9136    {
9137       get { return icon; }
9138       set
9139       {
9140          icon = value;
9141          incref icon;
9142          if(created)
9143             guiApp.interfaceDriver.SetIcon(this, value);
9144       }
9145    };
9146    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9147    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9148    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9149    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9150    property bool nativeDecorations { get { return (bool)nativeDecorations && rootWindow == this; } set { nativeDecorations = value; } };
9151    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9152    
9153 private:
9154    // Data
9155    //char * yo;
9156    Window prev, next;
9157    WindowBits style;       // Window Style
9158    char * caption;            // Name / Caption
9159    Window parent;    // Parent window
9160    OldList children;          // List of children in Z order
9161    Window activeChild;     // Child window having focus
9162    Window activeClient;
9163    Window previousActive;  // Child active prior to activating the default child
9164    Window master;          // Window owning and receiving notifications concerning this window
9165    OldList slaves;            // List of windows belonging to this window
9166    Display display;        // Display this window is drawn into
9167
9168    Point position;         // Position in parent window client area
9169    Point absPosition;      // Absolute position
9170    Point clientStart;      // Client area position from (0,0) in this window
9171    Size size;              // Size
9172    Size clientSize;        // Client area size
9173    Size scrollArea;        // Virtual Scroll area size
9174    Size reqScrollArea;     // Requested virtual area size
9175    Point scroll;           // Virtual area scrolling position
9176    public ScrollBar sbh, sbv;        // Scrollbar window handles
9177    Cursor cursor;        // Mouse cursor used for this window
9178    WindowState state;
9179    PopupMenu menuBar;
9180    StatusBar statusBar;
9181    Button sysButtons[3];
9182    char * fileName;
9183    Box clientArea;         // Client Area box clipped to parent
9184    Key setHotKey;
9185    HotKeySlot hotKey;        // HotKey for this window
9186    int numDocuments;
9187    int numPositions;
9188    Menu menu;
9189    ScrollFlags scrollFlags;// Window Scrollbar Flags
9190    int id;                 // Control ID
9191    int documentID;
9192    ColorAlpha background;  // Background color used to draw the window area
9193    Color foreground;
9194    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9195    OldList childrenCycle;     // Cycling order
9196    OldLink cycle;             // Element of parent's cycling order
9197    OldList childrenOrder;     // Circular Z-Order
9198    OldLink order;             // Element of parent's circular Z-Order
9199    Window modalSlave;      // Slave window blocking this window's interaction
9200
9201    Window rootWindow;      // Topmost system managed window
9202    void * windowHandle;    // System window handle
9203
9204    DialogResult returnCode;// Return code for modal windows
9205   
9206    Point sbStep;           // Scrollbar line scrolling steps
9207
9208    Anchor stateAnchor;
9209    SizeAnchor stateSizeAnchor;
9210
9211    Anchor normalAnchor;
9212    SizeAnchor normalSizeAnchor;
9213
9214    Size skinMinSize;       // Minimal window size based on style
9215    Point scrolledPos;      // Scrolled position
9216    Box box;                // Window box clipped to parent
9217    Box * against;          // What to clip the box to
9218
9219    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9220    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9221    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9222    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9223    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9224    Point scrolledArea;     // Distance to scroll area by
9225    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9226
9227    OldList hotKeys;           // List of the hotkeys of all children
9228    Window defaultControl;  // Default child control
9229    Size minSize;
9230    Size maxSize;
9231
9232    ColorAlpha * palette;   // Color palette used for this window
9233
9234    int caretSize;          // Size of caret, non zero if a caret is present
9235    Point caretPos;         // Caret position
9236
9237    void * systemParent;    // Parent System Window for embedded windows
9238
9239    int iconID;
9240    int numIcons;
9241    int positionID;
9242
9243    Mutex mutex;
9244    WindowState lastState;
9245
9246    FileMonitor fileMonitor
9247    {
9248       this, FileChange { modified = true };
9249
9250       bool OnFileNotify(FileChange action, char * param)
9251       {
9252          incref this;
9253          fileMonitor.StopMonitoring();
9254          if(OnFileModified(action, param))
9255             fileMonitor.StartMonitoring();
9256          delete this;
9257          return true;
9258       }
9259    };
9260    FontResource setFont, systemFont;
9261    FontResource usedFont;
9262    FontResource captionFont;
9263    OldList resources;
9264    FileDialog saveDialog;
9265    Anchor anchor;
9266    SizeAnchor sizeAnchor;
9267
9268    // FormDesigner data
9269    ObjectInfo object;
9270    Window control;
9271    Extent * tempExtents; //[4];
9272    BitmapResource icon;
9273    void * windowData;
9274    CreationActivationOption creationActivation;
9275    struct
9276    {
9277       bool active:1;            // true if window and ancestors are active
9278       bool acquiredInput:1;     // true if the window is processing state based input
9279       bool modifiedDocument:1;
9280       bool disabled:1;          // true if window cannot interact
9281       bool isForegroundWindow:1;// true while a root window is being activated
9282       bool visible:1;           // Visibility flag
9283       bool destroyed:1;         // true if window is being destroyed
9284       bool anchored:1;          // true if this window is repositioned when the parent resizes
9285       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9286       bool mouseInside:1;
9287       bool positioned:1;
9288       bool created:1;
9289       bool is3D:1;
9290       bool mergeMenus:1;
9291       bool modifyVirtArea:1;
9292       bool noAutoScrollArea:1;
9293       bool closing:1;
9294       bool autoCreate:1;
9295       bool setVisible:1;      // FOR FORM DESIGNER
9296       bool wasCreated:1;
9297       bool fullRender:1;
9298       bool moveable:1;
9299       bool alphaBlend:1;
9300       bool composing:1;
9301       bool useSharedMemory:1;
9302       bool resized:1;
9303       bool saving:1;
9304       bool nativeDecorations:1;
9305       bool manageDisplay:1;
9306    }; 
9307
9308    WindowController controller;
9309    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9310 };
9311
9312 public class CommonControl : Window
9313 {
9314    // creationActivation = doNothing;
9315 };
9316
9317 public class Percentage : float
9318 {
9319    char * OnGetString(char * string, float * fieldData, bool * needClass)
9320    {
9321       int c;
9322       int last = 0;
9323       sprintf(string, "%.2f", this);
9324       c = strlen(string)-1;
9325       for( ; c >= 0; c--)
9326       {
9327          if(string[c] != '0') 
9328             last = Max(last, c);
9329          if(string[c] == '.')
9330          {
9331             if(last == c)
9332                string[c] = 0;
9333             else
9334                string[last+1] = 0;
9335             break;
9336          }
9337       }
9338       return string;
9339    }
9340 };
9341
9342 public void ApplySkin(Class c, char * name, void ** vTbl)
9343 {
9344    char className[1024];
9345    Class sc;
9346    OldLink d;
9347    int m;
9348
9349    subclass(Window) wc = (subclass(Window))c;
9350    subclass(Window) base = (subclass(Window))c.base;
9351
9352    sprintf(className, "%sSkin_%s", name, c.name);
9353    wc.pureVTbl = c._vTbl;
9354    c._vTbl = new void *[c.vTblSize];
9355    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9356    sc = eSystem_FindClass(c.module.application, className);
9357    
9358    if(vTbl)
9359    {
9360       for(m = 0; m < c.base.vTblSize; m++)
9361       {
9362          if(c._vTbl[m] == base.pureVTbl[m])
9363             c._vTbl[m] = vTbl[m];
9364       }
9365    }
9366    if(sc)
9367    {
9368       for(m = 0; m < c.vTblSize; m++)
9369       {
9370          if(sc._vTbl[m] != wc.pureVTbl[m])
9371             c._vTbl[m] = sc._vTbl[m];
9372       }
9373    }
9374       
9375    for(d = c.derivatives.first; d; d = d.next)
9376    {
9377       ApplySkin(d.data, name, c._vTbl);
9378    }
9379 }
9380
9381 public void UnapplySkin(Class c)
9382 {
9383    char className[1024];
9384    Class sc;
9385    subclass(Window) wc = (subclass(Window))c;
9386    subclass(Window) base = (subclass(Window))c.base;
9387    OldLink d;
9388
9389    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9390    {
9391       delete c._vTbl;
9392       c._vTbl = wc.pureVTbl;
9393       wc.pureVTbl = null;
9394    }
9395
9396    for(d = c.derivatives.first; d; d = d.next)
9397    {
9398       UnapplySkin(d.data);
9399    }
9400 }
9401 /*
9402 void CheckFontIntegrity(Window window)
9403 {
9404    Window c;
9405    if(window)
9406    {
9407       if(window.usedFont && window.usedFont.font == 0xecececec)
9408       {
9409          FontResource uf = window.usedFont;
9410          char * className = window._class.name;
9411          char * text = window.text;
9412          Print("");
9413       }
9414       for(c = window.firstChild; c; c = c.next)
9415          CheckFontIntegrity(c);
9416    }
9417 }*/
9418
9419 public class ControllableWindow : Window
9420 {
9421    /*WindowController controller;
9422    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9423    ~ControllableWindow() { delete controller; }*/
9424 }
9425
9426 class WindowControllerInterface : ControllableWindow
9427 {
9428    bool OnKeyDown(Key key, unichar ch)
9429    {
9430       bool result = ((int(*)())(void *)controller.OnKeyDown)((void *)controller.controlled, (void *)controller, key, ch);
9431       if(result)
9432          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown](controller.window, key, ch);
9433       return result;
9434    }
9435
9436    bool OnKeyUp(Key key, unichar ch)
9437    {
9438       bool result = ((int(*)())(void *)controller.OnKeyUp)((void *)controller.controlled, (void *)controller, key, ch);
9439       if(result)
9440          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp](controller.window, key, ch);
9441       return result;
9442    }
9443
9444    bool OnKeyHit(Key key, unichar ch)
9445    {
9446       bool result = ((int(*)())(void *)controller.OnKeyHit)((void *)controller.controlled, (void *)controller, key, ch);
9447       if(result)
9448          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit](controller.window, key, ch);
9449       return result;
9450    }
9451
9452    bool OnMouseMove(int x, int y, Modifiers mods)
9453    {
9454       bool result = ((int(*)())(void *)controller.OnMouseMove)((void *)controller.controlled, (void *)controller, x, y, mods);
9455       if(result)
9456          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove](controller.window, x, y, mods);
9457       return result;
9458    }
9459
9460    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9461    {
9462       bool result = ((int(*)())(void *)controller.OnLeftButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9463       if(result)
9464          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown](controller.window, x, y, mods);
9465       return result;
9466    }
9467
9468    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9469    {
9470       bool result = ((int(*)())(void *)controller.OnLeftButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9471       if(result)
9472          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp](controller.window, x, y, mods);
9473       return result;
9474    }
9475
9476    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9477    {
9478       bool result = ((int(*)())(void *)controller.OnLeftDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9479       if(result)
9480          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick](controller.window, x, y, mods);
9481       return result;
9482    }
9483
9484    bool OnRightButtonDown(int x, int y, Modifiers mods)
9485    {
9486       bool result = ((int(*)())(void *)controller.OnRightButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9487       if(result)
9488          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown](controller.window, x, y, mods);
9489       return result;
9490    }
9491
9492    bool OnRightButtonUp(int x, int y, Modifiers mods)
9493    {
9494       bool result = ((int(*)())(void *)controller.OnRightButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9495       if(result)
9496          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp](controller.window, x, y, mods);
9497       return result;
9498    }
9499
9500    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9501    {
9502       bool result = ((int(*)())(void *)controller.OnRightDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9503       if(result)
9504          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick](controller.window, x, y, mods);
9505       return result;
9506    }
9507
9508    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9509    {
9510       bool result = ((int(*)())(void *)controller.OnMiddleButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9511       if(result)
9512          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown](controller.window, x, y, mods);
9513       return result;
9514    }
9515
9516    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9517    {
9518       bool result = ((int(*)())(void *)controller.OnMiddleButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9519       if(result)
9520          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp](controller.window, x, y, mods);
9521       return result;
9522    }
9523
9524    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9525    {
9526       bool result = ((int(*)())(void *)controller.OnMiddleDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9527       if(result)
9528          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick](controller.window, x, y, mods);
9529       return result;
9530    }
9531
9532    void OnResize(int width, int height)
9533    {
9534       ((int(*)())(void *)controller.OnResize)((void *)controller.controlled, (void *)controller, width, height);
9535       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize](controller.window, width, height);
9536    }
9537
9538    void OnRedraw(Surface surface)
9539    {
9540       ((int(*)())(void *)controller.OnRedraw)((void *)controller.controlled, (void *)controller, surface);
9541       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw](controller.window, surface);
9542    }
9543
9544    bool OnCreate()
9545    {
9546       bool result = ((int(*)())(void *)controller.OnCreate)((void *)controller.controlled, (void *)controller);
9547       if(result)
9548          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate](controller.window);
9549       return result;
9550    }
9551 }
9552
9553 public class WindowController<class V>
9554 {
9555 public:
9556    property Window window
9557    {
9558       set
9559       {
9560          uint size = class(Window).vTblSize;
9561          if(value)
9562          {
9563             windowVTbl = new void *[size];
9564             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9565             if(value._vTbl == value._class._vTbl)
9566             {
9567                value._vTbl = new void *[value._class.vTblSize];
9568                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9569             }
9570             {
9571                int c;
9572                for(c = 0; c < size; c++)
9573                {
9574                   void * function = class(WindowControllerInterface)._vTbl[c];
9575                   if(function != DefaultFunction)
9576                      value._vTbl[c] = function;
9577                   else
9578                      value._vTbl[c] = windowVTbl[c];
9579                }
9580             }
9581          }
9582          else
9583             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9584          window = value;
9585       }
9586       get { return window; }
9587    }
9588    property V controlled
9589    {
9590       set { controlled = value; }
9591       get { return controlled; }
9592    }
9593    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9594    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9595    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9596    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9597    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9598    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9599    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9600    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9601    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9602    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9603    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9604    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9605    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9606    virtual void V::OnResize(WindowController controller, int width, int height);
9607    virtual void V::OnRedraw(WindowController controller, Surface surface);
9608    virtual bool V::OnCreate(WindowController controller);
9609
9610 private:
9611    int (** windowVTbl)();   
9612    V controlled;
9613    Window window;
9614
9615    ~WindowController()
9616    {
9617       delete windowVTbl;
9618    }
9619 }