home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / misc / vcb.lha / vcb / vcbclass.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-15  |  19.3 KB  |  637 lines

  1. #include <exec/memory.h>
  2. #include <intuition/intuition.h>
  3. #include <intuition/cghooks.h>
  4. #include <intuition/classes.h>
  5. #include <intuition/classusr.h>
  6. #include <intuition/gadgetclass.h>
  7. #include <intuition/icclass.h>
  8. #include <intuition/imageclass.h>
  9. #include <libraries/gadtools.h>
  10. #include <functions.h>
  11. #include <stdlib.h>
  12. #include "vcx.h"
  13. #include "vcb_private.h"
  14.  
  15. /***************************** private section ***************************/
  16.  
  17. static int max( int a, int b )
  18. {
  19.     return ( a > b ) ? a : b;
  20. }
  21.  
  22. static int min( int a, int b )
  23. {
  24.     return ( a < b ) ? a : b;
  25. }
  26.  
  27. /*
  28.  *    (re-)calculate horiz/vert.real.offset and horiz/vert.real/virtual.size.
  29.  *    According to these new values, modify horizontal and vertical scroller (if there).
  30.  *    This becomes necessary if the host window has changed its dimensions.
  31.  */
  32. static void dimension_vcb( Class *class, Object *object, struct GadgetInfo *gi )
  33. {
  34.     struct Gadget *gadget = (struct Gadget *)object;
  35.     struct VCB *vcb = INST_DATA( class, object );
  36.  
  37.     vcb->horiz.real.offset = gadget->LeftEdge;
  38.     if( gadget->Flags & GFLG_RELRIGHT )
  39.         vcb->horiz.real.offset += gi->gi_Domain.Width - 1;
  40.  
  41.     vcb->horiz.real.size = gadget->Width;
  42.     if( gadget->Flags & GFLG_RELWIDTH )
  43.         vcb->horiz.real.size += gi->gi_Domain.Width - 1;
  44.  
  45.     vcb->vert.real.offset = gadget->TopEdge;
  46.     if( gadget->Flags & GFLG_RELBOTTOM )
  47.         vcb->vert.real.offset += gi->gi_Domain.Height - 1;
  48.  
  49.     vcb->vert.real.size = gadget->Height;
  50.     if( gadget->Flags & GFLG_RELHEIGHT )
  51.         vcb->vert.real.size += gi->gi_Domain.Height - 1;
  52.  
  53.     if( vcb->flags & VCBF_HSCROLLER )
  54.         vcb->horiz.real.size -= vcb->size_width;
  55.     vcb->horiz.virtual.size =
  56.         min( vcb->horiz.total, vcb->horiz.real.size / vcb->horiz.unit );
  57.  
  58.     if( vcb->horiz.virtual.offset > vcb->horiz.total - vcb->horiz.virtual.size )
  59.         vcb->horiz.virtual.offset = max( 0, vcb->horiz.total - vcb->horiz.virtual.size );
  60.  
  61.     if( vcb->flags & VCBF_VSCROLLER )
  62.         vcb->vert.real.size -= vcb->size_height;
  63.     vcb->vert.virtual.size =
  64.         min( vcb->vert.total, vcb->vert.real.size / vcb->vert.unit );
  65.  
  66.     if( vcb->vert.virtual.offset > vcb->vert.total - vcb->vert.virtual.size )
  67.         vcb->vert.virtual.offset = max( 0, vcb->vert.total - vcb->vert.virtual.size );
  68.  
  69. #ifdef DEBUG
  70.     kprintf( "dimension_vcb : GadgetInfo %08lx window %08lx requester %08lx\n",
  71.         gi, gi->gi_Window, gi->gi_Requester );
  72. #endif
  73.     if( vcb->horiz.scroller )
  74.         SetGadgetAttrs( vcb->horiz.scroller,
  75.             gi->gi_Window, gi->gi_Requester,
  76.             PGA_Total, vcb->horiz.total,
  77.             PGA_Visible, vcb->horiz.virtual.size,
  78.             PGA_Top, vcb->horiz.virtual.offset,
  79.             TAG_DONE );
  80.  
  81. #ifdef DEBUG
  82.     kprintf( "dimension_vcb : vert.total %ld .visible %ld .top %ld\n",
  83.         vcb->vert.total, vcb->vert.virtual.size, vcb->vert.virtual.offset );
  84. #endif
  85.     if( vcb->vert.scroller )
  86.         SetGadgetAttrs( vcb->vert.scroller,
  87.             gi->gi_Window, gi->gi_Requester,
  88.             PGA_Total, vcb->vert.total,
  89.             PGA_Visible, vcb->vert.virtual.size,
  90.             PGA_Top, vcb->vert.virtual.offset,
  91.             TAG_DONE );
  92. #ifdef DEBUG
  93.     kprintf( "dimension_vcb : complete\n" );
  94. #endif
  95. }
  96.  
  97. static void scroll_vcb( struct RastPort *rp, struct VCB *vcb, int dx, int dy )
  98. {
  99.     ScrollRaster( rp, vcb->horiz.unit * dx, vcb->vert.unit * dy,
  100.         vcb->horiz.real.offset, vcb->vert.real.offset,
  101.         vcb->horiz.real.offset + vcb->horiz.unit * vcb->horiz.virtual.size - 1,
  102.         vcb->vert.real.offset + vcb->vert.unit * vcb->vert.virtual.size - 1 );
  103. }
  104.  
  105. static struct TagItem VCBBoolTags[] =
  106. {
  107.     { VCBGA_Interim, VCBF_INTERIM },
  108.     { VCBGA_HScroller, VCBF_HSCROLLER },
  109.     { VCBGA_VScroller, VCBF_VSCROLLER },
  110.     { VCBGA_HBorder, VCBF_HBORDER },
  111.     { VCBGA_VBorder, VCBF_VBORDER },
  112.     { TAG_DONE }
  113. };
  114.  
  115. static ULONG newVCB( Class *class, Object *object, struct opSet *ops )
  116. {
  117.     struct VCBperClassData *vpcd = (struct VCBperClassData *)class->cl_UserData;
  118.     APTR new, size_image;
  119.     struct VCB *vcb;
  120.     struct DrawInfo *drawinfo;
  121.     int imagesize;
  122.  
  123.     if( new = (APTR)DoSuperMethodA( class, object, (Msg)ops ) )
  124.     {
  125.         struct Gadget *gadget = (struct Gadget *)new, *previous;
  126.  
  127.         vcb = INST_DATA( class, new );
  128.         InitSemaphore( &vcb->semaphore );
  129.         vcb->exposure = (struct Hook *)GetTagData( VCBGA_ExposureHook, 0, ops->ops_AttrList );
  130.         vcb->flags = GetTagData( VCBGA_Flags, 0, ops->ops_AttrList );
  131.         vcb->flags = PackBoolTags( vcb->flags, ops->ops_AttrList, VCBBoolTags );
  132.  
  133.         /* we (and VCX) need these to create system imagery */
  134.         drawinfo = (struct DrawInfo *)GetTagData( SYSIA_DrawInfo, 0, ops->ops_AttrList );
  135.         imagesize = GetTagData( SYSIA_Size, SYSISIZE_MEDRES, ops->ops_AttrList );
  136.  
  137.         if( !drawinfo )
  138.             goto failure;
  139.  
  140.         /* gives new meaning to SIZEIMAGE as it is used here to dimension our geometry :-) */
  141.         size_image = NewObject( NULL, "sysiclass",
  142.                                 SYSIA_Which, SIZEIMAGE,
  143.                                 SYSIA_DrawInfo, drawinfo,
  144.                                 SYSIA_Size, imagesize,
  145.                                 TAG_DONE );
  146.         if( !size_image )
  147.             goto failure;
  148.         vcb->size_width = ((struct Image *)size_image)->Width;
  149.         vcb->size_height = ((struct Image *)size_image)->Height;
  150.         DisposeObject( size_image );
  151.  
  152.         vcb->horiz.total = GetTagData( VCBGA_HTotal, 1, ops->ops_AttrList );
  153.         vcb->horiz.unit = GetTagData( VCBGA_HUnit, 1, ops->ops_AttrList );
  154.         vcb->horiz.virtual.offset = GetTagData( VCBGA_HOffset, 0, ops->ops_AttrList );
  155.         vcb->horiz.scroller = NULL;
  156.         vcb->vert.total = GetTagData( VCBGA_VTotal, 1, ops->ops_AttrList );
  157.         vcb->vert.unit = GetTagData( VCBGA_VUnit, 1, ops->ops_AttrList );
  158.         vcb->vert.virtual.offset = GetTagData( VCBGA_VOffset, 0, ops->ops_AttrList );
  159.         vcb->vert.scroller = NULL;
  160.  
  161.         if( !vcb->horiz.unit || !vcb->vert.unit )
  162.             goto failure;
  163.  
  164.         dimension_vcb( class, new, ops->ops_GInfo );
  165.  
  166.         previous = gadget;
  167.         if( vcb->flags & VCBF_HSCROLLER )
  168.         {
  169.             vcb->horiz.scroller = NewObject( vpcd->VCXClass, NULL,
  170.                 GA_ID, HORIZ_ID,
  171.                 ( gadget->Flags & GFLG_RELRIGHT ) ? GA_RelRight : GA_Left, gadget->LeftEdge,
  172.                 ( ( gadget->Flags & GFLG_RELBOTTOM ) || ( gadget->Flags & GFLG_RELHEIGHT ) ) ?
  173.                     GA_RelBottom : GA_Top,
  174.                 gadget->TopEdge + gadget->Height - vcb->size_height,
  175.                 ( gadget->Flags & GFLG_RELWIDTH ) ? GA_RelWidth : GA_Width,
  176.                 gadget->Width - vcb->size_width,
  177.                 PGA_Freedom, FREEHORIZ,
  178.                 ICA_TARGET, new,
  179.                 PGA_Total, vcb->horiz.total,
  180.                 PGA_Top, vcb->horiz.virtual.offset,
  181.                 PGA_Visible, vcb->horiz.virtual.size,
  182.                 SYSIA_DrawInfo, drawinfo,
  183.                 SYSIA_Size, imagesize,
  184.                 GA_Previous, previous,
  185.                 GA_BottomBorder, ( vcb->flags & VCBF_HBORDER ),
  186.                 TAG_DONE );
  187.             if( !vcb->horiz.scroller )
  188.                 goto failure;
  189.             previous = (struct Gadget *)vcb->horiz.scroller;
  190.         }
  191.         else
  192.             vcb->horiz.scroller = NULL;
  193.         if( vcb->flags & VCBF_VSCROLLER )
  194.         {
  195.             vcb->vert.scroller = NewObject( vpcd->VCXClass, NULL,
  196.                 GA_ID, VERT_ID,
  197.                 ( ( gadget->Flags & GFLG_RELRIGHT ) || ( gadget->Flags & GFLG_RELWIDTH ) ) ?
  198.                     GA_RelRight : GA_Left,
  199.                 gadget->LeftEdge + gadget->Width - vcb->size_width,
  200.                 ( gadget->Flags & GFLG_RELBOTTOM ) ? GA_RelBottom : GA_Top, gadget->TopEdge,
  201.                 ( gadget->Flags & GFLG_RELHEIGHT ) ? GA_RelHeight : GA_Height,
  202.                 gadget->Height - vcb->size_height,
  203.                 PGA_Freedom, FREEVERT,
  204.                 PGA_Total, vcb->vert.total,
  205.                 PGA_Top, vcb->vert.virtual.offset,
  206.                 PGA_Visible, vcb->vert.virtual.size,
  207.                 ICA_TARGET, new,
  208.                 SYSIA_DrawInfo, drawinfo,
  209.                 SYSIA_Size, imagesize,
  210.                 GA_Previous, previous,
  211.                 GA_RightBorder, ( vcb->flags & VCBF_VBORDER ),
  212.                 TAG_DONE );
  213.             if( !vcb->vert.scroller )
  214.                 goto failure;
  215.         }
  216.         else
  217.             vcb->vert.scroller = NULL;
  218.     }
  219.     return (ULONG)new;
  220. failure:
  221.     if( vcb->vert.scroller )
  222.         DisposeObject( vcb->vert.scroller );
  223.     if( vcb->horiz.scroller )
  224.         DisposeObject( vcb->horiz.scroller );
  225.     DoSuperMethod( class, new, OM_DISPOSE );
  226.     return 0;
  227. }
  228.  
  229. /*
  230.  *    This one does the callback to the hook function which handles the
  231.  *    actual rendition within the virtual coordinate box.
  232.  *
  233.  *    It performs a non-locking arbitration for the right to call the hook.
  234.  *    By obtaining the semaphore the client can savely modify the background data
  235.  *    on which the hook function's work is based (client should run a RefreshGList()
  236.  *    afterwards to get the display updated).
  237.  *
  238.  *    The hook function is passed the object handle. It uses it to retrieve
  239.  *    each necessary geometrical information through GetAttr().
  240.  *
  241.  *    The command ID `VCBCMD_Render┤ is only there for compliance with system-wide standards.
  242.  *    The callback function is not supposed to do anything besides rendering.
  243.  *    Arguments l, t, w, h are the left and top coordinates, width and height of the
  244.  *    rectangle that was exposed and has to be re-rendered. These are NOT pixels but
  245.  *    virtual coordinate units. You get pixel coordinates by taking these times horiz.unit
  246.  *    or vert.unit, respectively. The coordinates are relative to the visible box rather
  247.  *    than absolute within the virtual coordinate plane ( 0,0 means the top/left corner of
  248.  *    the box).
  249.  */
  250. static void fix_exposure( Class *class, Object *object, struct RastPort *rp,
  251.     int l, int t, int w, int h )
  252. {
  253.     struct VCB *vcb = INST_DATA( class, object );
  254.  
  255.     if( vcb->exposure && ( w > 0 ) && ( h > 0 ) )
  256.         if( AttemptSemaphore( &vcb->semaphore ) )
  257.         {
  258.             CallHook( vcb->exposure, object, VCBCMD_RENDER, rp, l, t, w, h );
  259.             ReleaseSemaphore( &vcb->semaphore );
  260.         }
  261. }
  262.  
  263. static void display( Class *class, Object *object,
  264.     struct RastPort *rp, struct GadgetInfo *gi )
  265. {
  266.     struct VCB *vcb = INST_DATA( class, object );
  267.  
  268.     /* calculate dimensions */
  269.     dimension_vcb( class, object, gi );
  270.  
  271.     SetAPen( rp, 0 );
  272.     SetBPen( rp, 0 );
  273.     SetDrMd( rp, JAM2 );
  274.     RectFill( rp,
  275.         vcb->horiz.real.offset,
  276.         vcb->vert.real.offset,
  277.         vcb->horiz.real.offset + vcb->horiz.real.size - 1,
  278.         vcb->vert.real.offset + vcb->vert.real.size - 1 );
  279.  
  280.     fix_exposure( class, object, rp,
  281.         0, 0, vcb->horiz.virtual.size, vcb->vert.virtual.size );
  282. }
  283.  
  284. static ULONG renderVCB( Class *class, Object *object, struct gpRender *gpr )
  285. {
  286.     display( class, object, gpr->gpr_RPort, gpr->gpr_GInfo );
  287.     return 1;
  288. }
  289.  
  290. /* return 1 if at least one offset did truly change */
  291. static int shift_vcb( Class *class, Object *object, int new_hoff, int new_voff,
  292.     struct GadgetInfo *gi, ULONG flags )
  293. {
  294.     struct VCB *vcb = INST_DATA( class, object );
  295.     struct RastPort *rp;
  296.     int ignore, dx, dy, recycle = 0;
  297.  
  298.     /* if display is locked, do nothing */
  299.     if( !AttemptSemaphore( &vcb->semaphore ) ) return 0;
  300.  
  301.     rp = ObtainGIRPort( gi );
  302.     if( new_hoff > vcb->horiz.total - vcb->horiz.virtual.size )
  303.         new_hoff = vcb->horiz.total - vcb->horiz.virtual.size;
  304.  
  305.     if( new_voff > vcb->vert.total - vcb->vert.virtual.size )
  306.         new_voff = vcb->vert.total - vcb->vert.virtual.size;
  307.  
  308.     /* if the VCBF_INTERIM flag is not set, ignore interim updates */
  309.     ignore = ( !( vcb->flags & VCBF_INTERIM ) && ( flags & OPUF_INTERIM ) );
  310.  
  311.     dx = new_hoff - vcb->horiz.virtual.offset;
  312.     dy = new_voff - vcb->vert.virtual.offset;
  313.  
  314.     if( rp && !ignore )
  315.     {
  316.         /* this flags indicates if the shift leaves some old imagery visible */
  317.         recycle = ( abs( dx ) < vcb->horiz.virtual.size ) &&
  318.                     ( abs( dy ) < vcb->vert.virtual.size );
  319.  
  320.         /* scroll_vcb() only if sensible to do so */
  321.         if( ( dx || dy ) && recycle )
  322.             scroll_vcb( rp, vcb, dx, dy );
  323.     }
  324.     if( !ignore )
  325.     {
  326.         vcb->horiz.virtual.offset = new_hoff;
  327.         vcb->vert.virtual.offset = new_voff;
  328.     }
  329.     if( rp && !ignore )
  330.     {
  331.         /* now fix the newly exposed areas (max. 2 rectangles) */
  332.         if( !recycle )        /* nothing recyclable, complete re-draw */
  333.             fix_exposure( class, object, rp,
  334.                 0, 0, vcb->horiz.virtual.size, vcb->vert.virtual.size );
  335.         else if( dx >= 0 ) /* area exposed by horizontal shift (if any) is at right border */
  336.         {
  337.             if( dx )
  338.                 fix_exposure( class, object, rp,
  339.                     vcb->horiz.virtual.size - dx, 0, dx, vcb->vert.virtual.size );
  340.             if( dy > 0 ) /* exposed area at the bottom border */
  341.                 fix_exposure( class, object, rp,
  342.                     0, vcb->vert.virtual.size - dy, vcb->horiz.virtual.size - dx, dy );
  343.             else if( dy < 0 ) /* exposed area at the top border */
  344.                 fix_exposure( class, object, rp,
  345.                     0, 0, vcb->horiz.virtual.size - dx, -dy );
  346.         }
  347.         else if( dx < 0 ) /* exposed area at the left border */
  348.         {
  349.             fix_exposure( class, object, rp, 0, 0, -dx, vcb->vert.virtual.size );
  350.             if( dy > 0 ) /* exposed area at the bottom border */
  351.                 fix_exposure( class, object, rp,
  352.                     dx, vcb->vert.virtual.size - dy, vcb->horiz.virtual.size - dx, dy );
  353.             else if( dy < 0 ) /* exposed area at the top border */
  354.                 fix_exposure( class, object, rp,
  355.                     dx, 0, vcb->horiz.virtual.size - dx, -dy );
  356.         }
  357.     }
  358.     ReleaseSemaphore( &vcb->semaphore );
  359.     ReleaseGIRPort( rp );
  360.     return ( dx || dy );
  361. }
  362.  
  363. static ULONG updateVCB( Class *class, Object *object, struct opUpdate *opu )
  364. {
  365.     struct VCB *vcb = INST_DATA( class, object );
  366.     struct TagItem *ti, *tstate = opu->opu_AttrList;
  367.  
  368.     DoSuperMethodA( class, object, (Msg)opu );    /* pass on our ID */
  369.     switch( GetTagData( GA_ID, 0, opu->opu_AttrList ) )
  370.     {
  371.     case HORIZ_ID:
  372.         shift_vcb( class, object,
  373.             GetTagData( PGA_Top, vcb->horiz.virtual.offset, opu->opu_AttrList ),
  374.             vcb->vert.virtual.offset,
  375.             opu->opu_GInfo, opu->opu_Flags );
  376.         break;
  377.     case VERT_ID:
  378.         shift_vcb( class, object,
  379.             vcb->horiz.virtual.offset,
  380.             GetTagData( PGA_Top, vcb->vert.virtual.offset, opu->opu_AttrList ),
  381.             opu->opu_GInfo, opu->opu_Flags );
  382.         break;
  383.     }
  384.     return 1;
  385. }
  386.  
  387. static ULONG setVCB( Class *class, Object *object, struct opSet *ops )
  388. {
  389.     struct VCB *vcb = INST_DATA( class, object );
  390.     struct RastPort *rp;
  391.     struct TagItem *ti, *tstate = ops->ops_AttrList;
  392.  
  393. #ifdef DEBUG
  394.     kprintf( "setVCB : GadgetInfo %08lx, gi_Window %08lx, gi_Requester %08lx\n",
  395.         ops->ops_GInfo, ops->ops_GInfo->gi_Window, ops->ops_GInfo->gi_Requester );
  396. #endif
  397.     while( ti = NextTagItem( &tstate ) )
  398.     {
  399. #ifdef DEBUG1
  400.         kprintf( "setVCB : Tag %08lx, Data %08lx\n", ti->ti_Tag, ti->ti_Data );
  401. #endif
  402.         switch( ti->ti_Tag )
  403.         {
  404.         case VCBGA_ExposureHook:
  405.             ObtainSemaphore( &vcb->semaphore );        /* disallow usage of hook */
  406.             vcb->exposure = (struct Hook *)ti->ti_Data;
  407.             ReleaseSemaphore( &vcb->semaphore );    /* permit usage of hook */
  408.             break;
  409.         case VCBGA_HOffset:
  410.             if( shift_vcb( class, object,
  411.                 ti->ti_Data, vcb->vert.virtual.offset, ops->ops_GInfo, 0 ) )
  412.             {
  413.                 /* now move the scroll bars, too */
  414.                 if( vcb->horiz.scroller )
  415.                     SetGadgetAttrs( (struct Gadget *)vcb->horiz.scroller,
  416.                         ops->ops_GInfo->gi_Window, ops->ops_GInfo->gi_Requester,
  417.                         PGA_Top, vcb->horiz.virtual.offset,
  418.                         TAG_DONE );
  419.                 if( vcb->vert.scroller )
  420.                     SetGadgetAttrs( (struct Gadget *)vcb->vert.scroller,
  421.                         ops->ops_GInfo->gi_Window, ops->ops_GInfo->gi_Requester,
  422.                         PGA_Top, vcb->vert.virtual.offset,
  423.                         TAG_DONE );
  424.             }
  425.             break;
  426.         case VCBGA_HTotal:
  427.             vcb->horiz.total = ti->ti_Data;
  428.             if( rp = ObtainGIRPort( ops->ops_GInfo ) )
  429.             {
  430.                 display( class, object, rp, ops->ops_GInfo );
  431.                 ReleaseGIRPort( rp );
  432.             }
  433.             break;
  434.         case VCBGA_HUnit:
  435.             vcb->horiz.unit = ti->ti_Data;
  436.             if( rp = ObtainGIRPort( ops->ops_GInfo ) )
  437.             {
  438.                 display( class, object, rp, ops->ops_GInfo );
  439.                 ReleaseGIRPort( rp );
  440.             }
  441.             break;
  442.         case VCBGA_VOffset:
  443.             if( shift_vcb( class, object,
  444.                 vcb->horiz.virtual.offset, ti->ti_Data, ops->ops_GInfo, 0 ) )
  445.             {
  446.                 /* now move the scroll bars, too */
  447.                 if( vcb->horiz.scroller )
  448.                     SetGadgetAttrs( (struct Gadget *)vcb->horiz.scroller,
  449.                         ops->ops_GInfo->gi_Window, ops->ops_GInfo->gi_Requester,
  450.                         PGA_Top, vcb->horiz.virtual.offset,
  451.                         TAG_DONE );
  452.                 if( vcb->vert.scroller )
  453.                     SetGadgetAttrs( (struct Gadget *)vcb->vert.scroller,
  454.                         ops->ops_GInfo->gi_Window, ops->ops_GInfo->gi_Requester,
  455.                         PGA_Top, vcb->vert.virtual.offset,
  456.                         TAG_DONE );
  457.             }
  458.             break;
  459.         case VCBGA_VTotal:
  460.             vcb->vert.total = ti->ti_Data;
  461.             if( rp = ObtainGIRPort( ops->ops_GInfo ) )
  462.             {
  463.                 display( class, object, rp, ops->ops_GInfo );
  464.                 ReleaseGIRPort( rp );
  465.             }
  466.             break;
  467.         case VCBGA_VUnit:
  468.             vcb->vert.unit = ti->ti_Data;
  469.             if( rp = ObtainGIRPort( ops->ops_GInfo ) )
  470.             {
  471.                 display( class, object, rp, ops->ops_GInfo );
  472.                 ReleaseGIRPort( rp );
  473.             }
  474.             break;
  475.         case VCBGA_Interim:
  476.             if( ti->ti_Data )
  477.                 vcb->flags |= VCBF_INTERIM;
  478.             else
  479.                 vcb->flags &= ~VCBF_INTERIM;
  480.             break;
  481.         }
  482.     }
  483. #ifdef DEBUG
  484.     kprintf( "setVCB : complete\n" );
  485. #endif
  486.     return 1;
  487. }
  488.  
  489. static ULONG getVCB( Class *class, Object *object, struct opGet *opg )
  490. {
  491.     struct VCB *vcb = INST_DATA( class, object );
  492.  
  493.     switch( opg->opg_AttrID )
  494.     {
  495.     case VCBGA_ExposureHook:
  496.         *opg->opg_Storage = (ULONG)vcb->exposure;
  497.         return 1;
  498.     case VCBGA_HOffset:
  499.         *opg->opg_Storage = vcb->horiz.virtual.offset;
  500.         return 1;
  501.     case VCBGA_HTotal:
  502.         *opg->opg_Storage = vcb->horiz.total;
  503.         return 1;
  504.     case VCBGA_HUnit:
  505.         *opg->opg_Storage = vcb->horiz.unit;
  506.         return 1;
  507.     case VCBGA_HSize:
  508.         *opg->opg_Storage = vcb->horiz.virtual.size;
  509.         return 1;
  510.     case VCBGA_VOffset:
  511.         *opg->opg_Storage = vcb->vert.virtual.offset;
  512.         return 1;
  513.     case VCBGA_VTotal:
  514.         *opg->opg_Storage = vcb->vert.total;
  515.         return 1;
  516.     case VCBGA_VUnit:
  517.         *opg->opg_Storage = vcb->vert.unit;
  518.         return 1;
  519.     case VCBGA_VSize:
  520.         *opg->opg_Storage = vcb->vert.virtual.size;
  521.         return 1;
  522.     case VCBGA_XOrigin:
  523.         *opg->opg_Storage = vcb->horiz.real.offset;
  524.         return 1;
  525.     case VCBGA_YOrigin:
  526.         *opg->opg_Storage = vcb->vert.real.offset;
  527.         return 1;
  528.     case VCBGA_Flags:
  529.         *opg->opg_Storage = vcb->flags;
  530.         return 1;
  531.     case VCBGA_Interim:
  532.         *opg->opg_Storage = ( vcb->flags & VCBF_INTERIM ) != 0;
  533.         return 1;
  534.     case VCBGA_HScroller:
  535.         *opg->opg_Storage = ( vcb->flags & VCBF_HSCROLLER ) != 0;
  536.         return 1;
  537.     case VCBGA_VScroller:
  538.         *opg->opg_Storage = ( vcb->flags & VCBF_VSCROLLER ) != 0;
  539.         return 1;
  540.     case VCBGA_HBorder:
  541.         *opg->opg_Storage = ( vcb->flags & VCBF_HBORDER ) != 0;
  542.         return 1;
  543.     case VCBGA_VBorder:
  544.         *opg->opg_Storage = ( vcb->flags & VCBF_VBORDER ) != 0;
  545.         return 1;
  546.     case VCBGA_Semaphore:
  547.         *opg->opg_Storage = (ULONG)( &vcb->semaphore );
  548.         return 1;
  549.     default:
  550.         return DoSuperMethodA( class, object, (Msg)opg );
  551.     }
  552. }
  553.  
  554. static ULONG disposeVCB( Class *class, Object *object, Msg msg )
  555. {
  556.     struct VCB *vcb = INST_DATA( class, object );
  557.  
  558.     if( vcb->horiz.scroller )
  559.         DisposeObject( vcb->horiz.scroller );
  560.     if( vcb->vert.scroller )
  561.         DisposeObject( vcb->vert.scroller );
  562.     return DoSuperMethodA( class, object, msg );
  563. }
  564.  
  565. static ULONG dispatchVCB( Class *class, Object *object, Msg msg )
  566. {
  567.     geta4();
  568.  
  569. #ifdef DEBUG
  570.     kprintf( "dispatchVCB : MethodID %08lx\n", msg->MethodID );
  571. #endif
  572.     switch( msg->MethodID )
  573.     {
  574.     case OM_NEW:
  575.         return newVCB( class, object, (struct opSet *)msg );
  576.     case OM_SET:
  577.         return setVCB( class, object, (struct opSet *)msg );
  578.     case OM_GET:
  579.         return getVCB( class, object, (struct opGet *)msg );
  580.     case OM_UPDATE:
  581.         return updateVCB( class, object, (struct opUpdate *)msg );
  582.     case OM_DISPOSE:
  583.         return disposeVCB( class, object, msg );
  584.     case GM_RENDER:
  585.         return renderVCB( class, object, (struct gpRender *)msg );
  586.     case GM_HITTEST:
  587.         return 0;
  588.     default:
  589.         return DoSuperMethodA( class, object, msg );
  590.     }
  591. }
  592.  
  593. /***************************** public section ***************************/
  594.  
  595. /*
  596.  *    initVCBClass() creates our BOOPSI class, freeVCBClass() tries to free it again.
  597.  *
  598.  *    These two functions are the ONLY targets to public reference within this module.
  599.  *    Everything else is PRIVATE (static) stuff.
  600.  */
  601. Class *initVCBClass( void )
  602. {
  603.     struct VCBperClassData *vpcd;
  604.     Class *class;
  605.  
  606.     if( vpcd = AllocMem( sizeof( struct VCBperClassData ), MEMF_PUBLIC ) )
  607.     {
  608.         if( vpcd->VCXClass = initVCXClass() )
  609.         {
  610.             if( class = MakeClass( NULL, "gadgetclass", NULL, sizeof( struct VCB ), 0 ) )
  611.             {
  612.                 SetupHook( &class->cl_Dispatcher, dispatchVCB, NULL );
  613.                 class->cl_UserData = (ULONG)vpcd;
  614.                 return class;
  615.             }
  616.             freeVCXClass( vpcd->VCXClass );
  617.         }
  618.         FreeMem( vpcd, sizeof( struct VCBperClassData ) );
  619.     }
  620.     return NULL;
  621. }
  622.  
  623. int freeVCBClass( Class *class )
  624. {
  625.     struct VCBperClassData *vpcd = (struct VCBperClassData *)class->cl_UserData;
  626.  
  627.     if( FreeClass( class ) )
  628.     {
  629.         if( freeVCXClass( vpcd->VCXClass ) )
  630.         {
  631.             FreeMem( vpcd, sizeof( struct VCBperClassData ) );
  632.             return 1;
  633.         }
  634.     }
  635.     return 0;
  636. }
  637.