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