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