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