home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / misc / vcb10a.lha / vcbclass.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-29  |  20.7 KB  |  712 lines

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