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