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