handling correction
[aros:aros.git] / AROS / workbench / devs / monitors / Compositor / compositorclass.c
1 /*
2     Copyright © 2010-2013, The AROS Development Team. All rights reserved.
3     $Id$
4 */
5
6 #define DEBUG 0
7 #if (DEBUG)
8 #define DTOGGLE(x) x
9 #define DMODE(x) x
10 #define DMOVE(x) x
11 #define DRECALC(x) x
12 #define DREDRAWBM(x) x
13 #define DREDRAWSCR(x) x
14 #define DSTACK(x) x
15 #define DUPDATE(x) x
16 #else
17 #define DTOGGLE(x)
18 #define DMODE(x)
19 #define DMOVE(x)
20 #define DRECALC(x)
21 #define DREDRAWBM(x)
22 #define DREDRAWSCR(x)
23 #define DSTACK(x)
24 #define DUPDATE(x)
25 #endif
26
27 #include <aros/debug.h>
28
29 #include <clib/alib_protos.h>
30 #include <proto/exec.h>
31 #include <proto/dos.h>
32 #include <proto/graphics.h>
33 #include <proto/intuition.h>
34 #include <proto/oop.h>
35 #include <proto/utility.h>
36
37 #include <graphics/view.h>
38 #include <hidd/graphics.h>
39
40 #include "compositor_intern.h"
41
42 #define COMPOSITOR_PREFS "SYS/compositor.prefs"
43 #define COMPOSITOR_PEFSTEMPLATE  "ABOVE/S,BELOW/S,LEFT/S,RIGHT/S,ALPHA/S"
44
45 enum
46 {
47     ARG_ABOVE = 0,
48     ARG_BELOW,
49     ARG_LEFT,
50     ARG_RIGHT,
51     ARG_ALPHA,
52     NOOFARGS
53 };
54
55
56 #ifdef GfxBase
57 #undef GfxBase
58 #endif
59 #define GfxBase compdata->GraphicsBase
60 #ifdef IntuitionBase
61 #undef IntuitionBase
62 #endif
63 #define IntuitionBase compdata->IntuitionBase
64
65 #define _RECT(x) x.MinX, x.MinY, x.MaxX, x.MaxY
66
67 #define MAX(a,b) a > b ? a : b
68 #define MIN(a,b) a < b ? a : b
69
70 BOOL isRectInRegion(struct Region *region, struct Rectangle *rect)
71 {
72     struct RegionRectangle *rrect = region->RegionRectangle;
73     struct Rectangle tmprect;
74
75     while (rrect)
76     {
77         if (AndRectRect(&rrect->bounds, rect, &tmprect))
78             return TRUE;
79
80         rrect = rrect->Next;
81     }
82     return FALSE;
83 }
84
85 static struct StackBitMapNode * HIDDCompositorFindBitMapStackNode(struct HIDDCompositorData * compdata, OOP_Object * bm)
86 {
87     struct StackBitMapNode * n = NULL;
88     
89     ForeachNode(&compdata->bitmapstack, n)
90     {
91         if (n->bm == bm)
92             return n;
93     }
94
95     return NULL;
96 }
97
98 struct Screen *HIDDCompositorFindBitMapScreen(struct HIDDCompositorData *compdata, OOP_Object *bm)
99 {
100     struct Screen *curScreen = NULL;
101
102     for (curScreen = IntuitionBase->FirstScreen; curScreen != NULL; curScreen = curScreen->NextScreen)
103     {
104         if (bm == HIDD_BM_OBJ(curScreen->RastPort.BitMap))
105         return curScreen;
106     }
107     
108     return (struct Screen *)NULL;
109 }
110
111 static VOID HIDDCompositorValidateBitMapPositionChange(OOP_Object * bm, SIPTR *newxoffset, SIPTR *newyoffset, LONG displayedwidth, LONG displayedheight)
112 {
113     IPTR width, height;
114     LONG neglimit, poslimit;
115
116     OOP_GetAttr(bm, aHidd_BitMap_Width, &width);
117     OOP_GetAttr(bm, aHidd_BitMap_Height, &height);
118
119     /* Check x position */
120     if (width > displayedwidth)
121     {
122         neglimit = displayedwidth - width;
123         poslimit = 0;
124     }
125     else
126     {
127         neglimit = 0;
128         poslimit = displayedwidth - width;
129     }
130
131     if (*(newxoffset) > poslimit)
132         *(newxoffset) = poslimit;
133     if (*(newxoffset) < neglimit)
134         *(newxoffset) = neglimit;
135
136     /* Check y position */
137     if (height > displayedheight)
138         neglimit = displayedheight - height; /* Limit for scroll */
139     else
140         neglimit = 0;
141     poslimit = displayedheight - 15; /* Limit for drag */
142
143     if (*(newyoffset) > poslimit)
144         *(newyoffset) = poslimit;
145     if (*(newyoffset) < neglimit)
146         *(newyoffset) = neglimit;
147 }
148
149 static VOID HIDDCompositorRecalculateVisibleRegions(struct HIDDCompositorData *compdata)
150 {
151     struct StackBitMapNode      *n = NULL, *tmpn;
152     struct Region               *dispvisregion = NULL;
153     ULONG                       oldflags = compdata->flags;
154
155     DRECALC(bug("[Compositor:%s] Display rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(compdata->displayrect)));
156
157     /*
158      * This function assumes bitmapstack is in correct Z order: 
159      * from topmost to bottom most
160      */
161     if ((dispvisregion = NewRegion()) != NULL)
162     {
163         OrRectRegion(dispvisregion, &compdata->displayrect);
164
165         compdata->flags &= ~COMPSTATEF_HASALPHA;
166
167         DRECALC(bug("[Compositor:%s] DisplayRegion @ 0x%p\n", __PRETTY_FUNCTION__, dispvisregion));
168
169         ForeachNodeSafe(&compdata->bitmapstack, n, tmpn)
170         {
171             /* Get bitmap bounding box in screen coordinates */
172             struct Rectangle tmprect;
173
174             n->sbmflags &= ~STACKNODEF_VISIBLE;
175
176             if (n->screenregion)
177                 ClearRegion(n->screenregion);
178             else
179                 n->screenregion = NewRegion();
180
181             if (n->screenregion)
182             {
183                 tmprect.MinX = n->leftedge;
184                 tmprect.MaxX = n->leftedge + OOP_GET(n->bm, aHidd_BitMap_Width) - 1;
185                 tmprect.MinY = n->topedge;
186                 tmprect.MaxY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
187
188                 DRECALC(bug("[Compositor:%s] Screen Rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(tmprect)));
189
190                 OrRectRegion(n->screenregion, &tmprect); // Start with the Screen's dimensions ..
191                 AndRegionRegion(dispvisregion, n->screenregion); // And adjust for the "Display"
192
193                 if (n->screenregion->RegionRectangle)
194                 {
195                     AndRectRect(&n->screenregion->bounds, &compdata->displayrect, &n->screenvisiblerect);
196
197                     if (!(n->sbmflags & STACKNODEF_HASALPHA))
198                         ClearRectRegion(dispvisregion, &n->screenvisiblerect);
199                     else
200                     {
201                         compdata->flags |= COMPSTATEF_HASALPHA;
202                         if (!(compdata->alpharegion))
203                             compdata->alpharegion = NewRegion();
204                         
205                         OrRectRegion(compdata->alpharegion, &n->screenvisiblerect);
206                     }
207
208                     if (!(compdata->capabilities & COMPF_ABOVE) && !(n->sbmflags & COMPF_ABOVE))
209                     {
210                         tmprect.MinX = compdata->displayrect.MinX;
211                         tmprect.MaxX = compdata->displayrect.MaxX;
212                         tmprect.MinY = compdata->displayrect.MinY;
213                         tmprect.MaxY = n->topedge - 1;
214                         ClearRectRegion(dispvisregion, &tmprect);
215                     }
216                     if (!(compdata->capabilities & COMPF_BELOW) && !(n->sbmflags & COMPF_BELOW))
217                     {
218                         tmprect.MinX = compdata->displayrect.MinX;
219                         tmprect.MaxX = compdata->displayrect.MaxX;
220                         tmprect.MinY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height);
221                         tmprect.MaxY = compdata->displayrect.MaxY;
222                         ClearRectRegion(dispvisregion, &tmprect);
223                     }
224                     if (!(compdata->capabilities & COMPF_LEFT) && !(n->sbmflags & COMPF_LEFT))
225                     {
226                         tmprect.MinX = compdata->displayrect.MinX;
227                         tmprect.MaxX = n->leftedge - 1;
228                         tmprect.MinY = n->topedge;
229                         tmprect.MaxY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
230                         ClearRectRegion(dispvisregion, &tmprect);
231                     }
232                     if (!(compdata->capabilities & COMPF_RIGHT) && !(n->sbmflags & COMPF_RIGHT))
233                     {
234                         tmprect.MinX = n->leftedge + OOP_GET(n->bm, aHidd_BitMap_Width);
235                         tmprect.MaxX = compdata->displayrect.MaxX;
236                         tmprect.MinY = n->topedge;
237                         tmprect.MaxY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
238                         ClearRectRegion(dispvisregion, &tmprect);
239                     }
240                     n->sbmflags |= STACKNODEF_VISIBLE;
241                 }
242
243                 DRECALC(bug("[Compositor:%s] Bitmap 0x%x, topedge %d, visible %d, [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, 
244                             n->bm, n->topedge, (n->sbmflags & STACKNODEF_VISIBLE), _RECT(n->screenvisiblerect)));
245             }
246             else
247             {
248                 DRECALC(bug("[Compositor:%s] Failed to create Screen Region\n", __PRETTY_FUNCTION__));
249             }
250         }
251         DisposeRegion(dispvisregion);
252         if (compdata->flags != oldflags)
253         {
254             ULONG newflags = (~oldflags) & compdata->flags;
255             DRECALC(bug("[Compositor:%s] Newly set flags %08x\n", __PRETTY_FUNCTION__, newflags));
256             if ((!(newflags & COMPSTATEF_HASALPHA)) && (oldflags & COMPSTATEF_HASALPHA))
257             {
258                 DRECALC(bug("[Compositor:%s] Alpha removed\n", __PRETTY_FUNCTION__));
259                 if (compdata->alpharegion)
260                     DisposeRegion(compdata->alpharegion);
261
262                 if (compdata->intermedbitmap)
263                     HIDD_Gfx_DisposeBitMap(compdata->gfx, compdata->intermedbitmap);
264
265                 compdata->alpharegion = NULL;
266                 compdata->intermedbitmap = NULL;
267             }
268         }
269     }
270     else
271     {
272         DRECALC(bug("[Compositor:%s] Failed to create Display Region\n", __PRETTY_FUNCTION__));
273     }
274 }
275
276 static HIDDT_ModeID FindBestHiddMode(struct HIDDCompositorData *compdata, ULONG width, ULONG height, ULONG depth, ULONG *res_depth)
277 {
278     HIDDT_ModeID mode = vHidd_ModeID_Invalid;
279     OOP_Object *sync, *pf;
280     IPTR w, h, d;
281     ULONG dw, dh, delta;
282     ULONG found_delta  = -1;
283     ULONG found_width  = 0;
284     ULONG found_height = 0;
285     ULONG found_depth  = 0;
286     HIDDT_ModeID found_mode = vHidd_ModeID_Invalid;
287
288     DMODE(bug("[%s] Finding best match for mode %ux%ux%u\n", __PRETTY_FUNCTION__, width, height, depth));
289
290     while ((mode = HIDD_Gfx_NextModeID(compdata->gfx, mode, &sync, &pf)) != vHidd_ModeID_Invalid)
291     {
292         BOOL match;
293
294         DMODE(bug("[%s] Checking mode 0x%08X... ", __PRETTY_FUNCTION__, mode));
295         if (OOP_GET(pf, aHidd_PixFmt_ColorModel) != vHidd_ColorModel_TrueColor)
296         {
297             DMODE(bug("Skipped (not truecolor)\n"));
298             continue;
299         }
300
301         OOP_GetAttr(sync, aHidd_Sync_HDisp, &w);
302         OOP_GetAttr(sync, aHidd_Sync_VDisp, &h);
303         OOP_GetAttr(pf, aHidd_PixFmt_Depth, &d);
304
305         dw = w > width  ? w - width  : w < width  ? width  - w : 1;
306         dh = h > height ? h - height : h < height ? height - h : 1;
307         delta = dw * dh;
308
309         match = FALSE;
310         if (delta < found_delta)
311         {
312             /* If mode resolution is closer to the needed one, we've got a better match */
313             found_delta  = delta;
314             found_width  = w;
315             found_height = h;
316
317             match = TRUE;
318         }
319         else if (delta == found_delta)
320         {
321             /* If resolution is the same as that of current candidate mode, we can look at depth. */
322             if (found_depth > depth)
323             {
324                 /*
325                  * Candidate mode if deeper than requested. We can supersede it with another mode
326                  * of smaller depth, but which still matches our request.
327                  */
328                 if ((d < found_depth) && (d >= depth))
329                     match = TRUE;
330             }
331             else if (found_depth < depth)
332             {
333                 /*
334                  * We want better depth than current candidate.
335                  * In this case anything deeper will do.
336                  */
337                 if (d > found_depth)
338                     match = TRUE;
339             }
340         }
341
342         if (match)
343         {
344             /*
345              * Mode with the same delta, but larger depth, may supersede
346              * previous mode, if we prefer deeper ones.
347              */
348             DMODE(bug("Selected (%ldx%ldx%ld, delta = %u)", w, h, d, delta));
349             found_depth = d;
350             found_mode  = mode;
351         }
352         DMODE(bug("\n"));
353     }
354
355     /* Store mode information */ 
356     compdata->displayrect.MinX = 0;
357     compdata->displayrect.MinY = 0;
358     compdata->displayrect.MaxX = found_width  - 1;
359     compdata->displayrect.MaxY = found_height - 1;
360     *res_depth = found_depth;
361
362     return found_mode;
363 }
364
365 static void UpdateDisplayMode(struct HIDDCompositorData *compdata)
366 {
367     struct StackBitMapNode *n;
368     IPTR modeid, width = 0, height = 0, depth;
369     OOP_Object *sync, *pf;
370     UBYTE comp_depth = 16;
371     ULONG found_depth;
372
373     DSTACK(bug("[Compositor] %s()\n", __PRETTY_FUNCTION__));
374
375     /*
376      * Examine all bitmaps in the stack to figure out the needed depth.
377      * We need a maximum depth of all depths in order to keep correct colors.
378      * But not less than 16 bits, because we can't compose on a LUT screen.
379      *
380      * If a LUT bitmap is present in the stack (depth < 9), we request truecolor
381      * screen for better color presentation.
382      *
383      * We examine bitmaps in reverse order, in this case 'sync' will hold
384      * information about the top bitmap when we exit the loop.
385      * Size of our composited mode needs to be as close as possible to that one.
386      */
387     for (n = (struct StackBitMapNode *)compdata->bitmapstack.mlh_TailPred;
388          n->n.mln_Pred; n = (struct StackBitMapNode *)n->n.mln_Pred)
389     {
390         if ((!(n->sbmflags & STACKNODEF_HASALPHA)) && (n->sbmflags & STACKNODEF_DISPLAYABLE))
391         {
392             OOP_GetAttr(n->bm, aHidd_BitMap_ModeID, &modeid);
393             HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
394
395             if (OOP_GET(pf, aHidd_PixFmt_ColorModel) == vHidd_ColorModel_TrueColor)
396             {
397                 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
398                 if (depth > comp_depth)
399                     comp_depth = depth;
400             }
401             else
402             {
403                 /*
404                  * If we have a LUT bitmap on stack, we request 24-bit screen
405                  * for better color transfer.
406                  */
407                 comp_depth = 24;
408             }
409         }
410         else
411         {
412             IPTR curwidth, curheight;
413             OOP_GetAttr(n->bm, aHidd_BitMap_Width, &curwidth);
414             OOP_GetAttr(n->bm, aHidd_BitMap_Height, &curheight);
415             if (curwidth > width)
416                 width = curwidth;
417             if (curheight > height)
418                 height = curheight;
419         }
420     }
421
422     if (sync)
423     {
424         /* Get the needed size */
425         OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
426         OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
427     }
428
429     DSTACK(bug("[%s] Prefered mode %ldx%ldx%d\n", __PRETTY_FUNCTION__, width, height, comp_depth));
430
431     modeid = FindBestHiddMode(compdata, width, height, comp_depth, &found_depth);
432     DSTACK(bug("[%s] Composition Display ModeID 0x%08X [current 0x%08X]\n", __PRETTY_FUNCTION__, modeid, compdata->screenmodeid));
433
434     if (modeid != compdata->screenmodeid)
435     {
436         /* The mode is different. Need to prepare information needed for compositing */
437         struct TagItem gctags[] =
438         {
439             { aHidd_GC_Foreground, 0x99999999 }, 
440             { TAG_DONE           , 0          }
441         };
442
443         /* Signal mode change */ 
444         compdata->screenmodeid = modeid;
445         compdata->modeschanged = TRUE;
446
447         /* Get gray foregound */
448         if (found_depth < 24)
449             gctags[0].ti_Data = 0x9492;
450
451         OOP_SetAttrs(compdata->gc, gctags);
452     }
453 }
454
455 static inline void HIDDCompositorRedrawBitmap(struct HIDDCompositorData *compdata, OOP_Object *renderTarget, struct StackBitMapNode *n, struct Rectangle *rect)
456 {
457     /* The given rectangle is already in screen coordinate system here */
458     ULONG blitwidth  = rect->MaxX - rect->MinX + 1;
459     ULONG blitheight = rect->MaxY - rect->MinY + 1;
460
461     DREDRAWBM(bug("[Compositor:%s] Redraw BitMap 0x%p, Rect[%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, n->bm,
462                   rect->MinX, rect->MinY, rect->MaxX, rect->MaxY));
463
464     if (!(n->sbmflags & STACKNODEF_HASALPHA))
465     {
466         DREDRAWBM(bug("[Compositor:%s] Blitting %dx%d [from %d, %d]\n", __PRETTY_FUNCTION__, blitwidth, blitheight, 
467               rect->MinX - n->leftedge, rect->MinY - n->topedge));
468
469         HIDD_Gfx_CopyBox(compdata->gfx, n->bm,
470                         /* Transform to source bitmap coord system */
471                         rect->MinX - n->leftedge, rect->MinY - n->topedge,
472                         renderTarget,
473                         rect->MinX, rect->MinY, blitwidth, blitheight,
474                         compdata->gc);
475     }
476     else
477     {
478         UBYTE *baseaddress;
479         ULONG width, height, banksize, memsize;
480         IPTR modulo;
481
482         DREDRAWBM(bug("[Compositor:%s] AlphaBlending %dx%d @ %d,%d to %d,%d\n", __PRETTY_FUNCTION__,
483               blitwidth, blitheight,
484               rect->MinX - n->leftedge, rect->MinY - n->topedge, rect->MinX, rect->MinY));
485
486         if (HIDD_BM_ObtainDirectAccess(n->bm, &baseaddress, &width, &height, &banksize, &memsize))
487         {
488             DREDRAWBM(bug("[Compositor:%s] Alpha baseaddress @ 0x%p\n", __PRETTY_FUNCTION__, baseaddress));
489             OOP_GetAttr(n->bm, aHidd_BitMap_BytesPerRow, &modulo);
490             HIDD_BM_PutAlphaImage(renderTarget, compdata->gfx , baseaddress + ((rect->MinY - n->topedge) * modulo) + ((rect->MinX - n->leftedge) << 2), modulo,
491                                                 rect->MinX, rect->MinY, blitwidth, blitheight);
492             HIDD_BM_ReleaseDirectAccess(n->bm);
493         }
494     }
495 }
496
497 static inline void ClearRect(struct HIDDCompositorData *compdata, OOP_Object *renderTarget, ULONG MinX, ULONG MinY, ULONG MaxX, ULONG MaxY)
498 {
499     DREDRAWSCR(bug("[Compositor:%s] Clearing [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
500                    MinX, MinY, MaxX, MaxY));
501
502     HIDD_BM_FillRect(renderTarget, compdata->gc,
503                      MinX, MinY, MaxX, MaxY);
504 }
505
506
507 static VOID HIDDCompositorRedrawAlphaRegions(struct HIDDCompositorData *compdata, struct Rectangle *drawrect)
508 {
509     struct Rectangle    alpharect;
510     struct StackBitMapNode *n;
511     OOP_Object *renderTarget = compdata->displaybitmap;
512
513     if (compdata->intermedbitmap)
514         renderTarget = compdata->intermedbitmap;
515
516     DREDRAWSCR(if (drawrect){ bug("[Compositor:%s] Rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT((*drawrect))); })
517
518     // Alpha Regions are drawn in reverse order incase they overlap..
519     for (n = (struct StackBitMapNode *)compdata->bitmapstack.mlh_TailPred;
520         n->n.mln_Pred; n = (struct StackBitMapNode *)n->n.mln_Pred)
521     {
522         if ((n->sbmflags & STACKNODEF_VISIBLE) &&
523             (n->sbmflags & STACKNODEF_HASALPHA) &&
524             (n->screenregion))
525         {
526             DREDRAWSCR(bug("[Compositor:%s] Alpha-ScreenRegion @ 0x%p ScreenBitMap @ 0x%p [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
527                                n->screenregion, n->bm, _RECT(n->screenvisiblerect)));
528
529             DREDRAWSCR(bug("[Compositor:%s] Compositing Visible Alpha Regions..\n", __PRETTY_FUNCTION__));
530
531             struct RegionRectangle * srrect = n->screenregion->RegionRectangle;
532             while (srrect)
533             {
534                 alpharect.MinX = srrect->bounds.MinX + n->screenregion->bounds.MinX;
535                 alpharect.MinY = srrect->bounds.MinY + n->screenregion->bounds.MinY;
536                 alpharect.MaxX = srrect->bounds.MaxX + n->screenregion->bounds.MinX;
537                 alpharect.MaxY = srrect->bounds.MaxY + n->screenregion->bounds.MinY;
538
539                 if ((drawrect) && !AndRectRect(drawrect, &alpharect, &alpharect))
540                     continue;
541
542                 DREDRAWSCR(bug("[Compositor:%s] Alpha-Region [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(alpharect)));
543
544                 HIDDCompositorRedrawBitmap(compdata, renderTarget, n, &alpharect);
545                 if (renderTarget == compdata->displaybitmap)
546                     HIDD_BM_UpdateRect(compdata->displaybitmap,
547                        alpharect.MinX, alpharect.MinY,
548                        alpharect.MaxX - alpharect.MinX + 1,
549                        alpharect.MaxY - alpharect.MinY + 1);
550
551                 srrect = srrect->Next;
552             }
553         }
554     }
555 }
556
557 static VOID HIDDCompositorRedrawVisibleRegions(struct HIDDCompositorData *compdata, struct Rectangle *drawrect)
558 {
559     struct Region       *dispvisregion = NULL;
560     struct Rectangle    tmprect;
561     OOP_Object *renderTarget = compdata->displaybitmap;
562     struct StackBitMapNode *n;
563
564     DREDRAWSCR(bug("[Compositor:%s] Redrawing screen (GfxBase @ 0x%p)\n", __PRETTY_FUNCTION__, GfxBase));
565
566     if (!(drawrect))
567     {
568         /* Recalculate visible regions */
569         HIDDCompositorRecalculateVisibleRegions(compdata);
570     }
571
572     if ((compdata->flags & COMPSTATEF_HASALPHA) && (compdata->intermedbitmap))
573         renderTarget = compdata->intermedbitmap;
574
575     if ((dispvisregion = NewRegion()) != NULL)
576     {
577         if (drawrect)
578             OrRectRegion(dispvisregion, drawrect);
579         else
580             OrRectRegion(dispvisregion, &compdata->displayrect);
581
582         DRECALC(bug("[Compositor:%s] Display rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(compdata->displayrect)));
583
584         ForeachNode(&compdata->bitmapstack, n)
585         {
586             if ((n->sbmflags & STACKNODEF_VISIBLE) &&
587                 (!(n->sbmflags & STACKNODEF_HASALPHA)) &&
588                 (n->screenregion))
589             {
590                 DREDRAWSCR(bug("[Compositor:%s] ScreenRegion @ 0x%p ScreenBitMap @ 0x%p [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
591                                n->screenregion, n->bm, _RECT(n->screenvisiblerect)));
592
593                 DREDRAWSCR(bug("[Compositor:%s] Redrawing Visible Screen Regions..\n", __PRETTY_FUNCTION__));
594                 // Render the visable regions ..
595                 struct RegionRectangle * srrect = n->screenregion->RegionRectangle;
596                 while (srrect)
597                 {
598                     tmprect.MinX = srrect->bounds.MinX + n->screenregion->bounds.MinX;
599                     tmprect.MinY = srrect->bounds.MinY + n->screenregion->bounds.MinY;
600                     tmprect.MaxX = srrect->bounds.MaxX + n->screenregion->bounds.MinX;
601                     tmprect.MaxY = srrect->bounds.MaxY + n->screenregion->bounds.MinY;
602
603                     if ((drawrect) && !AndRectRect(drawrect, &tmprect, &tmprect))
604                         continue;
605
606                     DREDRAWSCR(bug("[Compositor:%s] Region [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(tmprect)));
607
608                     HIDDCompositorRedrawBitmap(compdata, renderTarget, n, &tmprect);
609                     if (renderTarget == compdata->displaybitmap)
610                         HIDD_BM_UpdateRect(compdata->displaybitmap,
611                            tmprect.MinX, tmprect.MinY,
612                            tmprect.MaxX - tmprect.MinX + 1,
613                            tmprect.MaxY - tmprect.MinY + 1);
614
615                     srrect = srrect->Next;
616                 }
617                 ClearRegionRegion(n->screenregion, dispvisregion);
618             }
619         }
620         struct RegionRectangle * dispclrrect = dispvisregion->RegionRectangle;
621         while (dispclrrect)
622         {
623             struct HIDD_BackFillHookMsg clearmsg;
624
625             tmprect.MinX = dispclrrect->bounds.MinX + dispvisregion->bounds.MinX;
626             tmprect.MinY = dispclrrect->bounds.MinY + dispvisregion->bounds.MinY;
627             tmprect.MaxX = dispclrrect->bounds.MaxX + dispvisregion->bounds.MinX;
628             tmprect.MaxY = dispclrrect->bounds.MaxY + dispvisregion->bounds.MinY;
629
630             if ((drawrect) && !AndRectRect(drawrect, &tmprect, &tmprect))
631                 continue;
632
633             DREDRAWSCR(bug("[Compositor:%s] Render Display Void Region [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(tmprect)));
634
635             clearmsg.bounds = &tmprect;
636             clearmsg.offsetx = 0;
637             clearmsg.offsety = 0;
638             CallHookPkt(compdata->backfillhook, renderTarget, &clearmsg);
639             if (renderTarget == compdata->displaybitmap)
640                 HIDD_BM_UpdateRect(compdata->displaybitmap,
641                    tmprect.MinX, tmprect.MinY,
642                    tmprect.MaxX - tmprect.MinX + 1,
643                    tmprect.MaxY - tmprect.MinY + 1);
644
645             dispclrrect = dispclrrect->Next;
646         }
647         if (compdata->flags & COMPSTATEF_HASALPHA)
648         {
649             HIDDCompositorRedrawAlphaRegions(compdata, drawrect);
650         }
651         DisposeRegion(dispvisregion);
652     }
653     if (renderTarget != compdata->displaybitmap)
654     {
655         DREDRAWSCR(bug("[Compositor:%s] Copying Alpha Intermediary BitMap\n", __PRETTY_FUNCTION__, _RECT(tmprect)));
656         if (!(drawrect))
657         {
658             HIDD_Gfx_CopyBox(compdata->gfx, renderTarget,
659                     compdata->displayrect.MinX, compdata->displayrect.MinY,
660                     compdata->displaybitmap,
661                     compdata->displayrect.MinX, compdata->displayrect.MinY,
662                     compdata->displayrect.MaxX - compdata->displayrect.MinX + 1,
663                     compdata->displayrect.MaxY - compdata->displayrect.MinY + 1,
664                     compdata->gc);
665             HIDD_BM_UpdateRect(compdata->displaybitmap,
666                     compdata->displayrect.MinX, compdata->displayrect.MinY,
667                     compdata->displayrect.MaxX - compdata->displayrect.MinX + 1,
668                     compdata->displayrect.MaxY - compdata->displayrect.MinY + 1);
669         }
670         else
671         {
672             HIDD_Gfx_CopyBox(compdata->gfx, renderTarget,
673                     drawrect->MinX, drawrect->MinY,
674                     compdata->displaybitmap,
675                     drawrect->MinX, drawrect->MinY,
676                     drawrect->MaxX - drawrect->MinX + 1,
677                     drawrect->MaxY - drawrect->MinY + 1,
678                     compdata->gc);
679             HIDD_BM_UpdateRect(compdata->displaybitmap,
680                     drawrect->MinX, drawrect->MinY,
681                     drawrect->MaxX - drawrect->MinX + 1,
682                     drawrect->MaxY - drawrect->MinY + 1);
683         }
684     }
685 }
686
687 /*  
688
689 There are several cases that needs to be handled in this code. They are documented
690 below. Please read it before making changes.
691 etb     = existing topbitmap
692 ntb     = new top bitmap
693 sb      = screen bitmap
694 cb      = composited bitmap
695 fs      = covers full screen
696 nfs     = not covers full screen
697 mA      = mode "A"
698 mB      = mode "B"
699 disp()  = dispose
700 new()   = new
701
702 The resulting mode is always that of screen bitmap as set in "effect" column.
703 The composited bitmap always matches the resulting screen mode or is NULL.
704
705 | exiting screen situation          | change         | effect                               |
706 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - SAME MODE                               |
707 | etb->fs, mA, sb==etb, cb==NULL    | ntb->fs, mA    | sb==ntb, cb==NULL                    |
708 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->fs, mA    | sb==ntb, cb!=NULL                    |
709 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE           |
710 | etb->fs, mA, sb==etb, cb==NULL    | ntb->nfs, mA   | new(cb), sb==cb, cb!=NULL            |
711 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->nfs, mA   | sb==cb, cb!=NULL                     |
712 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - SAME MODE           |
713 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
714 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->fs, mA    | sb==ntb, cb!=NULL                    |
715 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE       |
716 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
717 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->nfs, mA   | sb==cb, cb!=NULL                     |
718
719
720 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - DIFFERENT MODES                         |
721 | etb->fs, mA, sb==etb, cb==NULL    | ntb->fs, mB    | sb==ntb, cb==NULL                    |
722 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->fs, mB    | disp(cb), sb==ntb, cb==NULL          |
723 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES     |
724 | etb->fs, mA, sb==etb, cb==NULL    | ntb->nfs, mB   | new(cb), sb==cb, cb!=NULL            |
725 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->nfs, mB   | disp(cb), new(cb), sb==cb, cb!=NULL  |
726 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - DIFFERENT MODES     |
727 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
728 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->fs, mB    | disp(cb), sb==ntb, cb==NULL          |
729 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES |
730 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
731 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->nfs, mB   | disp(cb), new(cb), sb==cb, cb!=NULL  |
732
733
734 | USE CASE: DRAGGING SCREEN DOWN                                                            |
735 | etb->fs, mA, sb==etb, cb==NULL    | ntb->nfs, mA   | new(cb), sb==cb                      |
736 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->nfs, mA   | sb==cb                               |
737 | USE CASE: DRAGGING SCREEN UP                                                              |
738 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->fs, mA    | sb==etb                              |
739 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
740
741 Resulting rules (order matters):
742
743 (a) if ((cb!=NULL) && (etb->mode!=ntb->mode)) {dispose(cb), cb=NULL}
744 (b) if ((ntb->nfs) && (cb==NULL)) new(cb)
745 (c) if (ntb->nfs) sb=cb
746 (d) if (ntb->fs) sb=ntb
747
748 Additional rule:
749 (e) if (oldsb!=sb) modeswitch(sb)
750
751 02.09.2011: we don't remember sb any more because we don't handle it in any way. Instead
752             we either have or don't have displaybitmap. If we have it, composition
753             is on (sb = cb). If we don't have it, composition is off (sb = ntb).
754 */
755 static BOOL HIDDCompositorToggleCompositing(struct HIDDCompositorData *compdata, BOOL newtop)
756 {
757     /* 
758      * If the topbitmap covers the complete screen, show it instead of 
759      * displaybitmap. Remember that screen bitmap -> composited bitmap
760      * mirroring has a negative impact on performance.
761      */
762     OOP_Object *oldcompositedbitmap = compdata->displaybitmap;
763     OOP_Object *newscreenbitmap = NULL;
764     struct TagItem bmtags[5];
765
766     BOOL ok = TRUE;
767
768     /* (a) If mode change is needed, enforce opening a new screen */
769     if (compdata->modeschanged)
770     {
771         DTOGGLE(bug("[Compositor:%s] Display Mode changed\n", __PRETTY_FUNCTION__));
772         compdata->displaybitmap = NULL;
773     }
774
775     bmtags[0].ti_Tag = aHidd_BitMap_Width;          bmtags[0].ti_Data = compdata->displayrect.MaxX + 1;
776     bmtags[1].ti_Tag = aHidd_BitMap_Height;         bmtags[1].ti_Data = compdata->displayrect.MaxY + 1;
777     bmtags[2].ti_Tag = aHidd_BitMap_Displayable;    bmtags[2].ti_Data = TRUE;
778     bmtags[3].ti_Tag = aHidd_BitMap_ModeID;         bmtags[3].ti_Data = compdata->screenmodeid;
779     bmtags[4].ti_Tag = TAG_DONE;                    bmtags[4].ti_Data = TAG_DONE;
780
781 #if (0)
782     /*
783      * This condition is enough as compositing allows only dragging screen down
784      * and not up/left/right at the moment.
785      */
786     if (topedge > 0)
787     {
788 #endif
789         /* (b) */
790         if (compdata->displaybitmap == NULL)
791         {
792             /*
793              * displaybitmap == NULL means we were in passthrough mode before,
794              * or have just changed display mode - set up screen for composition.
795              */
796             DTOGGLE(bug("[Compositor:%s] Initialising Display-Compositor..\n", __PRETTY_FUNCTION__));
797
798             if (compdata->fb)
799             {
800                 /*
801                  * If our display driver uses a framebuffer, we can reuse it.
802                  * Copy its original contents back into the bitmap which it replaced,
803                  * then change framebuffer's video mode.
804                  * Framebuffer is the only bitmap which can change its ModeID on the fly.
805                  */
806                 DTOGGLE(bug("[Compositor:%s] Using Display Famebuffer BitMap @ 0x%p\n", __PRETTY_FUNCTION__, compdata->fb));
807
808                  /* Do this comparison in order not to show the framebuffer twice */
809                 if (oldcompositedbitmap != compdata->fb)
810                 {
811                     /*
812                      * 1. It's legal to show the framebuffer itself. This causes copying
813                      *    back old bitmap contents and detaching from it.
814                      * 2. The result of this will always match compdata->fb.
815                      * 3. Internally this is a simple blit operation, it can't fail.
816                      */
817                     DTOGGLE(bug("[Compositor:%s] Copying old Famebuffer BitMap\n", __PRETTY_FUNCTION__));
818                     compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, compdata->fb, fHidd_Gfx_Show_CopyBack);
819                 }
820
821                 /* Switch display mode on the framebuffer. */
822                 OOP_SetAttrsTags(compdata->fb, aHidd_BitMap_ModeID, compdata->screenmodeid, TAG_DONE);
823                 /* We are now compositing on the framebuffer */
824                 compdata->displaybitmap = compdata->fb;
825             }
826             else
827             {
828                 /*
829                  * There's no framebuffer.
830                  * Create a new bitmap that will be used for compositing.
831                  */
832                 compdata->displaybitmap = HIDD_Gfx_NewBitMap(compdata->gfx, bmtags);
833                 DTOGGLE(bug("[Compositor:%s] Created Compositor Display BitMap @ 0x%p\n", __PRETTY_FUNCTION__, compdata->displaybitmap));
834
835                 /* Mode changed, this bitmap will be shown later */
836                 newscreenbitmap = compdata->displaybitmap;
837
838                 /* NewBitMap can fail, handle this */
839                 if (!newscreenbitmap)
840                     ok = FALSE;
841             }
842         }
843         else /* if (compdata->displaybitmap == NULL) */
844         {
845             /*
846              * We are already in compositing mode and will stay in it.
847              * Do not destroy our working bitmap.
848              */
849             oldcompositedbitmap = NULL;
850         }
851
852         if ((compdata->flags & COMPSTATEF_HASALPHA) && !(compdata->intermedbitmap))
853         {
854             compdata->intermedbitmap = HIDD_Gfx_NewBitMap(compdata->gfx, bmtags);
855             DTOGGLE(bug("[Compositor:%s] Allocated Alpha Intermediary BitMap @ 0x%p\n", __PRETTY_FUNCTION__, compdata->intermedbitmap));
856         }
857         /*
858          * (c) Here composition is turned on (displaybitmap != NULL).
859          * Redraw bitmap stack - compensate possible changes
860          */
861         if (ok)
862             HIDDCompositorRedrawVisibleRegions(compdata, NULL);
863 #if(0)
864     }
865     else if (oldcompositedbitmap || newtop)
866     {
867         /*
868          * (d) Set passthrough mode and display the frontmost bitmap.
869          * This is also triggered by 'newtop' parameter, which tells us
870          * that frontmost bitmap has been changed, and we need to display a new one.
871          * Old displaybitmap has been remembered in the beginning. If it's not
872          * NULL, it will be destroyed in the end.
873          */
874         newscreenbitmap = compdata->topbitmap;
875         compdata->displaybitmap = NULL;
876     }
877 #endif
878
879     DTOGGLE(bug("[Compositor:%s] oldcompbmp 0x%p, topbmp 0x%p, compbmp 0x%p, newscreenbmp 0x%p\n", __PRETTY_FUNCTION__,
880             oldcompositedbitmap, compdata->topbitmap, compdata->displaybitmap, newscreenbitmap));
881
882     /*
883      * (e) If the screenbitmap changed, show the new screenbitmap.
884      * We do it after refreshing, for better visual appearance.
885      */
886     if (newscreenbitmap)
887     {
888         IPTR w, h;
889
890         compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, newscreenbitmap, fHidd_Gfx_Show_CopyBack);
891         DTOGGLE(bug("[Compositor:%s] Displayed bitmap 0x%p, Show returned 0x%p\n", __PRETTY_FUNCTION__, newscreenbitmap, compdata->screenbitmap));
892
893         /* After Show we need Update for mirroring drivers */
894         if (compdata->screenbitmap)
895         {
896             OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Width, &w);
897             OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Height, &h);
898             HIDD_BM_UpdateRect(compdata->screenbitmap, 0, 0, w, h);
899         }
900     }
901
902     /*
903      * (a) - disposing of oldcompositingbitmap needs to happen after mode switch 
904      * since it could have been the current screenbitmap
905      */
906     if (oldcompositedbitmap && (oldcompositedbitmap != compdata->fb))
907     {
908         DTOGGLE(bug("[Compositor:%s] Disposing old working bitmap 0x%p\n", __PRETTY_FUNCTION__, oldcompositedbitmap));
909         HIDD_Gfx_DisposeBitMap(compdata->gfx, oldcompositedbitmap);
910     }
911
912     /* Handled */
913     compdata->modeschanged = FALSE;
914
915     return ok;
916 }
917
918 static VOID HIDDCompositorPurgeBitMapStack(struct HIDDCompositorData * compdata)
919 {
920     struct StackBitMapNode * curr, * next;
921
922     ForeachNodeSafe(&compdata->bitmapstack, curr, next)
923     {
924         if (curr->screenregion)
925             DisposeRegion(curr->screenregion);
926
927         FreeMem(curr, sizeof(struct StackBitMapNode));
928     }
929
930     NEWLIST(&compdata->bitmapstack);
931 }
932
933 static void HIDDCompositorShowSingle(struct HIDDCompositorData *compdata, OOP_Object *bm)
934 {
935     /* Show the single top bitmap */
936     compdata->topbitmap = bm;
937     compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, bm, fHidd_Gfx_Show_CopyBack);
938
939     /* Dispose working bitmap (if any) */
940     if (compdata->displaybitmap)
941     {
942         /* Be careful with the framebuffer */
943         if (compdata->displaybitmap != compdata->fb)
944             HIDD_Gfx_DisposeBitMap(compdata->gfx, compdata->displaybitmap);
945
946         /* This will deactivate us */
947         compdata->displaybitmap = NULL;
948     }
949 }
950
951 /* Emergency error recovery function */
952 static void HIDDCompositorReset(struct HIDDCompositorData *compdata)
953 {
954     /* Purge bitmap stack */
955     HIDDCompositorPurgeBitMapStack(compdata);
956
957     /*
958      * Reset our internal state so that next BitMapStackChanged
959      * causes complete reinitialization.
960      */
961     compdata->screenmodeid = vHidd_ModeID_Invalid;
962     compdata->screenbitmap = NULL;
963
964     compdata->flags &= ~COMPSTATEF_HASALPHA;
965 }
966
967 VOID CompositorParseConfig(struct HIDDCompositorData *compdata)
968 {
969     struct RDArgs *rdargs;
970     IPTR CompArgs[NOOFARGS] = { 0 };
971     TEXT CompConfig[1024];
972
973     /* use default amiga-like capabailities */
974     compdata->capabilities = COMPF_ABOVE;
975
976     rdargs = AllocDosObjectTags(DOS_RDARGS, TAG_END);
977     if (rdargs != NULL)
978     {
979         if (GetVar(COMPOSITOR_PREFS, CompConfig, 1024, GVF_GLOBAL_ONLY) != -1)
980         {
981             rdargs->RDA_Source.CS_Buffer = CompConfig;
982             rdargs->RDA_Source.CS_Length = strlen(rdargs->RDA_Source.CS_Buffer);
983             rdargs->RDA_DAList = (IPTR)NULL;
984             rdargs->RDA_Buffer = NULL;
985             rdargs->RDA_BufSiz = 0;
986             rdargs->RDA_ExtHelp = NULL;
987             rdargs->RDA_Flags = 0;
988
989             if (ReadArgs(COMPOSITOR_PEFSTEMPLATE, CompArgs, rdargs) != NULL)
990             {
991                 if (CompArgs[ARG_ABOVE])
992                     compdata->capabilities |= COMPF_ABOVE;
993                 else
994                     compdata->capabilities &= ~COMPF_ABOVE;
995                 
996                 if (CompArgs[ARG_BELOW])
997                     compdata->capabilities |= COMPF_BELOW;
998                 else
999                     compdata->capabilities &= ~COMPF_BELOW;
1000                 
1001                 if (CompArgs[ARG_LEFT])
1002                     compdata->capabilities |= COMPF_LEFT;
1003                 else
1004                     compdata->capabilities &= ~COMPF_LEFT;
1005                 
1006                 if (CompArgs[ARG_RIGHT])
1007                     compdata->capabilities |= COMPF_RIGHT;
1008                 else
1009                     compdata->capabilities &= ~COMPF_RIGHT;
1010
1011                 if (CompArgs[ARG_ALPHA])
1012                     compdata->capabilities |= COMPF_ALPHA;
1013                 else
1014                     compdata->capabilities &= ~COMPF_ALPHA;
1015
1016                 FreeArgs(rdargs);
1017             }
1018         }
1019         FreeDosObject(DOS_RDARGS, rdargs);
1020     }
1021 }
1022
1023 AROS_UFH3(void, CompositorDefaultBackFillFunc,
1024     AROS_UFHA(struct Hook *             , h,      A0),
1025     AROS_UFHA(OOP_Object *              , bm,     A2),
1026     AROS_UFHA(struct HIDD_BackFillHookMsg *  , msg,    A1))
1027 {
1028     AROS_USERFUNC_INIT
1029
1030     struct HIDDCompositorData *compdata = h->h_Data;
1031
1032     D(bug("[%s] HIDDCompositorData @ 0x%p\n", __PRETTY_FUNCTION__, compdata));
1033
1034     ClearRect(compdata, bm, msg->bounds->MinX, msg->bounds->MinY, msg->bounds->MaxX, msg->bounds->MaxY);
1035
1036     AROS_USERFUNC_EXIT
1037 }
1038
1039 /* PUBLIC METHODS */
1040 OOP_Object *METHOD(Compositor, Root, New)
1041 {
1042     o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
1043
1044     if (o)
1045     {
1046         OOP_MethodID disposemid;
1047         struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1048
1049         D(bug("[%s] Compositor @ 0x%p, data @ 0x%p\n", __PRETTY_FUNCTION__, o, compdata));
1050
1051         CompositorParseConfig(compdata);
1052
1053         D(bug("[%s] Composite Capabilities: %08lx\n", __PRETTY_FUNCTION__, compdata->capabilities));
1054
1055         compdata->screenmodeid = vHidd_ModeID_Invalid;
1056
1057         NEWLIST(&compdata->bitmapstack);
1058
1059         compdata->defaultbackfill.h_Entry = (HOOKFUNC)AROS_ASMSYMNAME(CompositorDefaultBackFillFunc);
1060         compdata->defaultbackfill.h_Data = compdata;
1061         compdata->backfillhook = &compdata->defaultbackfill;
1062
1063         InitSemaphore(&compdata->semaphore);
1064
1065         compdata->gfx = (OOP_Object *)GetTagData(aHidd_Compositor_GfxHidd, 0, msg->attrList);
1066         compdata->fb  = (OOP_Object *)GetTagData(aHidd_Compositor_FrameBuffer, 0, msg->attrList);
1067
1068         GfxBase = (APTR)OpenLibrary("graphics.library", 41);
1069         IntuitionBase = (APTR)OpenLibrary("intuition.library", 50);
1070
1071         /* GfxHidd is mandatory */
1072         if ((compdata->GraphicsBase) && (compdata->gfx != NULL))
1073         {
1074             /* Create GC object that will be used for drawing operations */
1075             compdata->gc = HIDD_Gfx_NewGC(compdata->gfx, NULL);
1076
1077             D(bug("[%s] Compositor GC @ %p\n", __PRETTY_FUNCTION__, compdata->gc));
1078
1079             if ((compdata->gfx) && (compdata->gc))
1080                 return o;
1081         }
1082
1083         /* Creation failed */
1084         disposemid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
1085         OOP_CoerceMethod(cl, o, &disposemid);
1086     }
1087
1088     return NULL;
1089 }
1090
1091 void METHOD(Compositor, Root, Dispose)
1092 {
1093
1094     D(
1095         struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1096         bug("[%s] HIDDCompositorData @ 0x%p\n", __PRETTY_FUNCTION__, compdata);
1097       )
1098
1099     OOP_DoSuperMethod(cl, o, &msg->mID);
1100 }
1101
1102 VOID METHOD(Compositor, Root, Get)
1103 {
1104     ULONG idx;
1105
1106     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1107
1108     if (IS_COMPOSITOR_ATTR(msg->attrID, idx))
1109     {
1110         switch (idx)
1111         {
1112             case aoHidd_Compositor_Capabilities:
1113             {
1114                 D(bug("[%s] Composite Capabilities: %lx\n", __PRETTY_FUNCTION__, compdata->capabilities));
1115                 *msg->storage = (IPTR)COMPF_ABOVE|COMPF_BELOW|COMPF_LEFT|COMPF_RIGHT;
1116                 return;
1117             }
1118             case aoHidd_Compositor_BackFillHook:
1119             {
1120                 D(bug("[%s] BackFillHook: 0x%p\n", __PRETTY_FUNCTION__, compdata->backfillhook));
1121                 *msg->storage = (IPTR)compdata->backfillhook;
1122                 return;
1123             }
1124         }
1125     }
1126     OOP_DoSuperMethod(cl, o, &msg->mID);
1127 }
1128
1129 VOID METHOD(Compositor, Root, Set)
1130 {
1131     ULONG idx;
1132
1133     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1134     struct TagItem *tag, *tstate = msg->attrList;
1135
1136     while ((tag = NextTagItem(&tstate)))
1137     {
1138         if (IS_COMPOSITOR_ATTR(tag->ti_Tag, idx))
1139         {
1140             switch (idx)
1141             {
1142                 case aoHidd_Compositor_Capabilities:
1143                 {
1144                     D(bug("[%s] Composite Capabilities: %lx -> %lx\n", __PRETTY_FUNCTION__, compdata->capabilities, tag->ti_Data));
1145                     compdata->capabilities = (ULONG)tag->ti_Data;
1146                     break;
1147                 }
1148                 case aoHidd_Compositor_BackFillHook:
1149                 {
1150                     if (tag->ti_Data)
1151                     {
1152                         D(bug("[%s] BackFillHook: 0x%p -> 0x%p\n", __PRETTY_FUNCTION__, compdata->backfillhook, tag->ti_Data));
1153                         compdata->backfillhook = (struct Hook *)tag->ti_Data;
1154                     }
1155                     else
1156                     {
1157                         D(bug("[%s] Default BackFillHook\n", __PRETTY_FUNCTION__));
1158                         compdata->backfillhook = &compdata->defaultbackfill;
1159                     }
1160                     break;
1161                 }
1162             }
1163         }
1164     }
1165
1166     OOP_DoSuperMethod(cl, o, &msg->mID);
1167 }
1168
1169 OOP_Object *METHOD(Compositor, Hidd_Compositor, BitMapStackChanged)
1170 {
1171     struct HIDD_ViewPortData *vpdata;
1172     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1173     struct StackBitMapNode *n;
1174     struct Screen *bmScreen;
1175     OOP_Object *bmpxfmt;
1176     int bmstdfmt;
1177     BOOL newtop = FALSE;
1178     BOOL ok = TRUE;
1179
1180     DSTACK(bug("[Compositor] %s: Top bitmap: 0x%lx\n", __PRETTY_FUNCTION__, msg->data->Bitmap));
1181
1182     LOCK_COMPOSITOR_WRITE
1183
1184     /* Free all items which are already on the list */
1185     HIDDCompositorPurgeBitMapStack(compdata);
1186
1187     if (!msg->data)
1188     {
1189         UNLOCK_COMPOSITOR
1190
1191         /* Blank screen */
1192         HIDDCompositorShowSingle(compdata, NULL);
1193
1194         /* We know we are inactive after this */
1195         *msg->active = FALSE;
1196         /* This can return NULL, it's okay */
1197         return compdata->screenbitmap;
1198     }
1199
1200     /* Copy bitmaps pointers to our stack */
1201     for (vpdata = msg->data; vpdata; vpdata = vpdata->Next)
1202     {
1203         n = AllocMem(sizeof(struct StackBitMapNode), MEMF_ANY | MEMF_CLEAR);
1204         if (!n)
1205         {
1206             /*
1207              * Error happened.
1208              * We need to reset own state and return NULL. graphics.library
1209              * falls back to no composition in this case.
1210              */
1211             DSTACK(bug("[Compositor] %s: Error allocating StackBitMapNode!!!\n", __PRETTY_FUNCTION__));
1212
1213             ok = FALSE;
1214             break;
1215         }
1216
1217         DSTACK(bug("[Compositor] %s: ViewPort 0x%p, offset (%d, %d)\n", __PRETTY_FUNCTION__, vpdata->vpe->ViewPort, vpdata->vpe->ViewPort->DxOffset, vpdata->vpe->ViewPort->DyOffset));
1218
1219         n->bm                   = vpdata->Bitmap;
1220         n->sbmflags             = STACKNODEF_DISPLAYABLE;
1221         n->leftedge             = vpdata->vpe->ViewPort->DxOffset;
1222         n->topedge              = vpdata->vpe->ViewPort->DyOffset;
1223
1224         n->screenregion = NewRegion();
1225
1226         if ((bmScreen = HIDDCompositorFindBitMapScreen(compdata, n->bm)) != NULL)
1227         {
1228             DSTACK(bug("[Compositor] %s: Screen @ 0x%p\n", __PRETTY_FUNCTION__, bmScreen));
1229             GetAttr(SA_CompositingFlags, (Object *)bmScreen, &n->sbmflags);
1230             DSTACK(bug("[Compositor] %s: CompositingFlags %08x\n", __PRETTY_FUNCTION__, n->sbmflags));
1231             n->sbmflags |= STACKNODEF_DISPLAYABLE;
1232         }
1233
1234         if (compdata->capabilities & COMPF_ALPHA)
1235         {
1236             bmpxfmt = (OOP_Object *)OOP_GET(n->bm, aHidd_BitMap_PixFmt);
1237             bmstdfmt = (int)OOP_GET(bmpxfmt, aHidd_PixFmt_StdPixFmt);
1238             DSTACK(bug("[Compositor] %s: Screen BitMap PixFmt %lx @ 0x%p\n", __PRETTY_FUNCTION__, bmstdfmt, bmpxfmt));
1239
1240             switch (bmstdfmt)
1241             {
1242                 case vHidd_StdPixFmt_ARGB32:
1243                 case vHidd_StdPixFmt_BGRA32:
1244                 case vHidd_StdPixFmt_RGBA32:
1245                 case vHidd_StdPixFmt_ABGR32:
1246                 {
1247                     DSTACK(bug("[Compositor] %s: Screen BitMap has Alpha\n", __PRETTY_FUNCTION__));
1248
1249                     n->sbmflags |= STACKNODEF_HASALPHA;
1250                     compdata->flags |= COMPSTATEF_HASALPHA;
1251                     break;
1252                 }
1253                 default:
1254                 {
1255                     n->sbmflags &= ~STACKNODEF_HASALPHA;
1256                     break;
1257                 }
1258             }
1259         }
1260
1261         if (!(n->sbmflags & STACKNODEF_HASALPHA))
1262         {
1263             if ((((BOOL)OOP_GET(n->bm, aHidd_BitMap_Displayable)) != TRUE))
1264                 n->sbmflags &= ~STACKNODEF_DISPLAYABLE;
1265         }
1266         AddTail((struct List *)&compdata->bitmapstack, (struct Node *)n);
1267     }
1268
1269     /* Switch mode if needed */
1270     UpdateDisplayMode(compdata);
1271
1272     if (msg->data->Bitmap != compdata->topbitmap)
1273     {
1274         /* Set the new pointer to top bitmap */
1275         compdata->topbitmap = msg->data->Bitmap;
1276         newtop = TRUE;
1277     }
1278
1279     if (ok)
1280     {
1281         /*
1282          * Validate bitmap offsets - they might not match the compositing rules taking
1283          * new displayedwidth/displayedheight values
1284          */
1285         ForeachNode(&compdata->bitmapstack, n)
1286         {
1287             HIDDCompositorValidateBitMapPositionChange(n->bm, &n->leftedge, &n->topedge, 
1288                                                         compdata->displayrect.MaxX + 1, compdata->displayrect.MaxY + 1);
1289             DSTACK(bug("[Compositor] %s: Bitmap 0x%p, display size %d x %d, validated position (%ld, %ld)\n", __PRETTY_FUNCTION__,
1290                        n->bm, compdata->displayrect.MaxX + 1, compdata->displayrect.MaxY + 1,
1291                        n->leftedge, n->topedge));
1292         }
1293
1294         /* Toogle compositing based on screen positions */
1295         ok = HIDDCompositorToggleCompositing(compdata, newtop);
1296     }
1297
1298     /* Handle error */
1299     if (!ok)
1300     {
1301         HIDDCompositorReset(compdata);
1302         HIDDCompositorShowSingle(compdata, msg->data->Bitmap);
1303     }
1304
1305     UNLOCK_COMPOSITOR
1306
1307     DSTACK(bug("[%s] Done, composited bitmap 0x%p\n", __PRETTY_FUNCTION__, compdata->displaybitmap));
1308
1309     /* Tell if the composition is active */
1310     *msg->active = compdata->displaybitmap ? TRUE : FALSE;
1311     /* Return actually displayed bitmap */
1312     return compdata->screenbitmap;
1313 }
1314
1315 VOID METHOD(Compositor, Hidd_Compositor, BitMapRectChanged)
1316 {
1317     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1318     OOP_Object                *renderTarget;
1319
1320     if (compdata->displaybitmap)
1321     {
1322         /* Composition is active, handle redraw if the bitmap is on screen */
1323         struct StackBitMapNode *n;
1324
1325         DUPDATE(bug("[%s] Bitmap 0x%p\n", __PRETTY_FUNCTION__, msg->bm));
1326
1327         LOCK_COMPOSITOR_READ
1328
1329         if (compdata->intermedbitmap)
1330             renderTarget = compdata->intermedbitmap;
1331         else
1332             renderTarget = compdata->displaybitmap;
1333
1334         n = HIDDCompositorFindBitMapStackNode(compdata, msg->bm);
1335         if (n && (n->sbmflags & STACKNODEF_VISIBLE))
1336         {
1337             struct Rectangle srcrect, dstandvisrect;
1338
1339             srcrect.MinX = n->leftedge + msg->x;
1340             srcrect.MinY = n->topedge + msg->y;
1341             srcrect.MaxX = srcrect.MinX + msg->width - 1; 
1342             srcrect.MaxY = srcrect.MinY + msg->height - 1;
1343             DUPDATE(bug("[%s] Bitmap rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, msg->x, msg->y, msg->x + msg->width - 1, msg->y + msg->height - 1));
1344
1345             DUPDATE(bug("[%s] Screen-relative rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(srcrect)));
1346
1347             struct RegionRectangle * srrect = n->screenregion->RegionRectangle;
1348             while (srrect)
1349             {
1350                 BOOL updateAlphaBmps = FALSE;
1351
1352                 dstandvisrect.MinX = srrect->bounds.MinX + n->screenregion->bounds.MinX;
1353                 dstandvisrect.MinY = srrect->bounds.MinY + n->screenregion->bounds.MinY;
1354                 dstandvisrect.MaxX = srrect->bounds.MaxX + n->screenregion->bounds.MinX;
1355                 dstandvisrect.MaxY = srrect->bounds.MaxY + n->screenregion->bounds.MinY;
1356
1357                 if (AndRectRect(&srcrect, &dstandvisrect, &dstandvisrect))
1358                 {
1359                     /* Intersection is valid. Blit. */
1360                     DUPDATE(bug("[%s] Clipped rect (%d, %d) - (%d, %d)\n", __PRETTY_FUNCTION__, _RECT(dstandvisrect)));
1361
1362                     if (!(n->sbmflags & STACKNODEF_HASALPHA))
1363                     {
1364                         if ((compdata->alpharegion) && (isRectInRegion(compdata->alpharegion, &dstandvisrect)))
1365                         {
1366                             DUPDATE(bug("[%s] ** Bitmap in Alpha Region!\n", __PRETTY_FUNCTION__));
1367                             updateAlphaBmps = TRUE;
1368                         }
1369                         HIDDCompositorRedrawBitmap(compdata, renderTarget, n, &dstandvisrect);
1370                     }
1371                     else
1372                     {
1373                         updateAlphaBmps = FALSE;
1374                         HIDDCompositorRedrawVisibleRegions(compdata, &dstandvisrect);
1375                     }
1376                     if (updateAlphaBmps)
1377                         HIDDCompositorRedrawAlphaRegions(compdata, &dstandvisrect);
1378
1379                     if (renderTarget != compdata->displaybitmap)
1380                     {
1381                         HIDD_Gfx_CopyBox(compdata->gfx, renderTarget,
1382                                 dstandvisrect.MinX, dstandvisrect.MinY,
1383                                 compdata->displaybitmap,
1384                                 dstandvisrect.MinX, dstandvisrect.MinY,
1385                                 dstandvisrect.MaxX - dstandvisrect.MinX + 1,
1386                                 dstandvisrect.MaxY - dstandvisrect.MinY + 1,
1387                                 compdata->gc);
1388                     }
1389
1390                     HIDD_BM_UpdateRect(compdata->displaybitmap,
1391                                        dstandvisrect.MinX, dstandvisrect.MinY,
1392                                        dstandvisrect.MaxX - dstandvisrect.MinX + 1,
1393                                        dstandvisrect.MaxY - dstandvisrect.MinY + 1);
1394                 }
1395                 srrect = srrect->Next;
1396             }
1397         }
1398
1399         UNLOCK_COMPOSITOR
1400         
1401         DUPDATE(bug("[%s] Done\n", __PRETTY_FUNCTION__));
1402     }
1403     else
1404     {
1405         /* In order to speed things up, we handle passthrough ourselves here. */
1406         HIDD_BM_UpdateRect(msg->bm, msg->x, msg->y, msg->width, msg->height);
1407     }
1408 }
1409
1410 IPTR METHOD(Compositor, Hidd_Compositor, BitMapPositionChange)
1411 {
1412     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1413     struct StackBitMapNode *n;
1414     IPTR disp_width, disp_height;
1415
1416     LOCK_COMPOSITOR_READ
1417
1418     n = HIDDCompositorFindBitMapStackNode(compdata, msg->bm);
1419     if (n)
1420     {
1421         /* The bitmap is on display. Validate against screen size */
1422         disp_width  = compdata->displayrect.MaxX + 1;
1423         disp_height = compdata->displayrect.MaxY + 1;
1424     }
1425     else
1426     {
1427         /* The bitmap is not displayed yet. Validate against its own ModeID size. */
1428         HIDDT_ModeID modeid = vHidd_ModeID_Invalid;
1429         OOP_Object *sync, *pf;
1430
1431         OOP_GetAttr(msg->bm, aHidd_BitMap_ModeID, &modeid);
1432
1433         if (modeid == vHidd_ModeID_Invalid)
1434         {
1435             /*
1436              * Nondisplayable bitmaps don't scroll.
1437              * In fact they simply can't get in here because MakeVPort() performs the validation.
1438              * But who knows what bug can slip into someone's software...
1439              */
1440             UNLOCK_COMPOSITOR
1441             return FALSE;
1442         }
1443
1444         HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
1445         OOP_GetAttr(sync, aHidd_Sync_HDisp, &disp_width);
1446         OOP_GetAttr(sync, aHidd_Sync_VDisp, &disp_height);
1447     }
1448
1449     DMOVE(bug("[%s] Validating bitmap 0x%p, position (%ld, %ld), limits %ld x %ld\n", __PRETTY_FUNCTION__,
1450           msg->bm, *msg->newxoffset, *msg->newyoffset, disp_width, disp_height));
1451
1452     HIDDCompositorValidateBitMapPositionChange(msg->bm, msg->newxoffset, msg->newyoffset,
1453                                                 disp_width, disp_height);
1454
1455     DMOVE(bug("[%s] Validated position (%ld, %ld)\n", __PRETTY_FUNCTION__, *msg->newxoffset, *msg->newyoffset));
1456
1457     if (n && ((*msg->newxoffset != n->leftedge) || (*msg->newyoffset != n->topedge)))
1458     {
1459         DMOVE(bug("[%s] Old position (%ld, %ld)\n", __PRETTY_FUNCTION__, n->leftedge, n->topedge));
1460
1461         /* Reflect the change if it happened */
1462         n->leftedge = *msg->newxoffset;
1463         n->topedge  = *msg->newyoffset;
1464
1465         if (compdata->topbitmap == msg->bm)
1466         {
1467             /*
1468              * If this is the frontmost bitmap, we may want to toggle compositing,
1469              * if it starts/stops covering the whole screen at one point.
1470              * We don't need to call HIDDCompositorRedrawVisibleRegions() here because
1471              * HIDDCompositorToggleCompositing() does this itself, for improved
1472              * visual appearance.
1473              */
1474             HIDDCompositorToggleCompositing(compdata, FALSE);    
1475         }
1476         else
1477             HIDDCompositorRedrawVisibleRegions(compdata, NULL);
1478     }
1479
1480     UNLOCK_COMPOSITOR
1481
1482     /* Return active state */
1483     return compdata->displaybitmap ? TRUE : FALSE;
1484 }
1485
1486 IPTR METHOD(Compositor, Hidd_Compositor, BitMapValidate)
1487 {
1488     if (IS_HIDD_BM(msg->bm))
1489         return TRUE;
1490     
1491     return FALSE;
1492 }
1493
1494 IPTR METHOD(Compositor, Hidd_Compositor, BitMapEnable)
1495 {
1496     if (IS_HIDD_BM(msg->bm))
1497     {
1498         if (!(OOP_GET(HIDD_BM_OBJ(msg->bm), aHidd_BitMap_Displayable)))
1499         {
1500             struct TagItem composittags[] = {
1501                 {aHidd_BitMap_Compositable, TRUE},
1502                 {TAG_DONE            , 0    }
1503             };
1504
1505             D(bug("[GfxCompositor]: Marking BitMap 0x%lx as Compositable\n", msg->bm));
1506             OOP_SetAttrs(HIDD_BM_OBJ(msg->bm), composittags);
1507         }
1508         return TRUE;
1509     }
1510
1511     return FALSE;
1512 }
1513
1514 #define NUM_Compositor_Root_METHODS 4
1515
1516 static const struct OOP_MethodDescr Compositor_Root_descr[] =
1517 {
1518     {(OOP_MethodFunc)Compositor__Root__New, moRoot_New},
1519     {(OOP_MethodFunc)Compositor__Root__Dispose, moRoot_Dispose},
1520     {(OOP_MethodFunc)Compositor__Root__Get, moRoot_Get},
1521     {(OOP_MethodFunc)Compositor__Root__Set, moRoot_Set},
1522     {NULL, 0}
1523 };
1524
1525 #define NUM_Compositor_Hidd_Compositor_METHODS 5
1526
1527 static const struct OOP_MethodDescr Compositor_Hidd_Compositor_descr[] =
1528 {
1529     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapStackChanged, moHidd_Compositor_BitMapStackChanged},
1530     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapRectChanged, moHidd_Compositor_BitMapRectChanged},
1531     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapPositionChange, moHidd_Compositor_BitMapPositionChange},
1532     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapValidate, moHidd_Compositor_BitMapValidate},
1533     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapEnable, moHidd_Compositor_BitMapEnable},
1534     {NULL, 0}
1535 };
1536
1537 const struct OOP_InterfaceDescr Compositor_ifdescr[] =
1538 {
1539     {Compositor_Root_descr, IID_Root, NUM_Compositor_Root_METHODS},
1540     {Compositor_Hidd_Compositor_descr, IID_Hidd_Compositor, NUM_Compositor_Hidd_Compositor_METHODS},
1541     {NULL, NULL}
1542 };