home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pencod.zip / STROKE.C < prev    next >
Text File  |  1993-11-05  |  65KB  |  1,184 lines

  1. /******************************************************************************
  2. *                                                                             *
  3. *   Name:  STROKE.C                                                           *
  4. *                                                                             *
  5. *   Copyright : COPYRIGHT IBM CORPORATION, 1993                               *
  6. *               LICENSED MATERIAL - PROGRAM PROPERTY OF IBM                   *
  7. *                                                                             *
  8. *   Description: This program processes all of the ink related functions      *
  9. *                for the application.                                         *
  10. *                                                                             *
  11. *  DISCLAIMER OF WARRANTIES.  The following [enclosed] code is                *
  12. *      sample code created by IBM Corporation. This sample code is not        *
  13. *      part of any standard or IBM product and is provided to you solely      *
  14. *      for  the purpose of assisting you in the development of your           *
  15. *      applications.  The code is provided "AS IS", without                   *
  16. *      warranty of any kind.  IBM shall not be liable for any damages         *
  17. *      arising out of your use of the sample code, even if they have been     *
  18. *      advised of the possibility of such damages.                            *
  19. *                                                                             *
  20. ******************************************************************************/
  21.  
  22. #define  INCL_PM
  23. #define  INCL_DOS
  24.  
  25. /******************************************************************************
  26. * System include files                                                        *
  27. ******************************************************************************/
  28. #include <os2.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <penpm.h>
  32.  
  33. /******************************************************************************
  34. * Application specific include file                                           *
  35. ******************************************************************************/
  36. #include "stroke.h"
  37.  
  38. /******************************************************************************
  39. * Exported routines                                                           *
  40. ******************************************************************************/
  41. HWND     APIENTRY InitTimedInk   ( HWND, MMTIME * );
  42. BOOL     APIENTRY PlayTimedInk   ( HWND );
  43. BOOL     APIENTRY StopTimedInk   ( HWND );
  44. BOOL     APIENTRY RecordTimedInk ( HWND );
  45. BOOL     APIENTRY PurgeTimedInk  ( HWND );
  46. BOOL     APIENTRY DestroyTimeInk ( HWND );
  47. MRESULT  EXPENTRY InkWinProc     ( HWND, ULONG, MRESULT, MRESULT );
  48. BOOL     APIENTRY InkTimedInk    ( HWND, MMTIME );
  49.  
  50. /******************************************************************************
  51. * Internal routines                                                           *
  52. ******************************************************************************/
  53. ULONG             TimeToPoints    ( PMYWINDOWDATA, MMTIME );
  54. BOOL              InkStroke       ( PMYWINDOWDATA, ULONG );
  55. BOOL              AppendStrokes   ( PMYWINDOWDATA, PSTROKEDATA );
  56. BOOL              ScaleStrokeData ( PMYWINDOWDATA );
  57. BOOL              EraseTimedInk  ( PMYWINDOWDATA );
  58.  
  59. /******************************************************************************
  60. * Used to track the current time reported from Multimedia.                    *
  61. ******************************************************************************/
  62. MMTIME *pCurrMMTime;
  63.  
  64. /******************************************************************************
  65. *                                                                             *
  66. * Subroutine: InitTimedInk                                                    *
  67. *                                                                             *
  68. *   Function: This function performs the initialization for the inking        *
  69. *             window. It allocates a block of memory for the data structure   *
  70. *             used by the inking window. It then creates a transparent window *
  71. *             to ink into.                                                    *
  72. *                                                                             *
  73. * Parameters: hwndParent - is the window handle to the parent window. The     *
  74. *                          parent window will be the window containing the    *
  75. *                          image to be annotated.                             *
  76. *                                                                             *
  77. * Internal                                                                    *
  78. * References: None                                                            *
  79. *                                                                             *
  80. * Pen For OS2                                                                 *
  81. * References: None                                                            *
  82. *                                                                             *
  83. ******************************************************************************/
  84. HWND APIENTRY InitTimedInk ( HWND hwndParent, MMTIME *pMMTime )
  85. {
  86.    PMYWINDOWDATA  pMyWindowData;
  87.    APIRET         rc;
  88.    HAB            hab;
  89.    HMQ            hmq;
  90.    QMSG           qmsg;
  91.    HWND           hwndInking;
  92.    static BOOL    WindowClassRegistered = FALSE;
  93.    RECTL          rcl;
  94.  
  95.    pMyWindowData = (PMYWINDOWDATA) malloc ( sizeof ( MYWINDOWDATA ) );
  96.  
  97.    /***************************************************************************
  98.    * Verify that the memory for the data structure has been allocated. If not *
  99.    * return a NULLHANDLE to signify an error condition.                       *
  100.    ***************************************************************************/
  101.    if ( pMyWindowData == NULL )
  102.    {
  103.       return ( NULLHANDLE );
  104.    };
  105.  
  106.    pCurrMMTime = pMMTime;
  107.  
  108.    pMyWindowData->hwndParent = hwndParent;
  109.    pMyWindowData->hab = WinQueryAnchorBlock ( hwndParent );
  110.  
  111.    /***************************************************************************
  112.    * Register the window class for the inking window, if it has not already   *
  113.    * been done.                                                               *
  114.    ***************************************************************************/
  115.    if ( !WindowClassRegistered )
  116.    {
  117.       /************************************************************************
  118.       * When the class is registered, reserve 4 more bytes to keep the        *
  119.       * pointer to pMyWindowData structure.                                   *
  120.       ************************************************************************/
  121.       if ( !WinRegisterClass ( pMyWindowData->hab,
  122.                                WC_INK_WINDOW,
  123.                                InkWinProc,
  124.                                CS_SYNCPAINT,
  125.                                sizeof ( PMYWINDOWDATA ) ) )
  126.       {
  127.          /*********************************************************************
  128.          * If the class has not been registered return a NULLHANDLE to        *
  129.          * signify an error condition.                                        *
  130.          *********************************************************************/
  131.          free ( pMyWindowData );
  132.          return ( NULLHANDLE );
  133.       };
  134.  
  135.       /************************************************************************
  136.       * If all goes well, set flag to indicate that the class has been        *
  137.       * already been registered.                                              *
  138.       ************************************************************************/
  139.       WindowClassRegistered = TRUE;
  140.    };
  141.  
  142.    /***************************************************************************
  143.    * Determine the size of the window, then create then inking window.        *
  144.    ***************************************************************************/
  145.    WinQueryWindowRect ( pMyWindowData->hwndParent, &rcl );
  146.    hwndInking = WinCreateWindow ( pMyWindowData->hwndParent,
  147.                                   WC_INK_WINDOW,
  148.                                   NULL,
  149.                                   0,
  150.                                   0,
  151.                                   0,
  152.                                   rcl.xRight,
  153.                                   rcl.yTop,
  154.                                   pMyWindowData->hwndParent,
  155.                                   HWND_TOP,
  156.                                   ID_INK_WINDOW,
  157.                                   (PVOID) pMyWindowData,
  158.                                   NULL );
  159.  
  160.    /***************************************************************************
  161.    * Verify that the window has been created. If not return NULLHANDLE to     *
  162.    * signify an error condition, else return the handle to the inking window. *
  163.    ***************************************************************************/
  164.    if ( !hwndInking )
  165.    {
  166.       free ( pMyWindowData );
  167.       return ( NULLHANDLE );
  168.    };
  169.    return ( hwndInking );
  170. }
  171.  
  172. /******************************************************************************
  173. *                                                                             *
  174. * Subroutine: DestroyTimedInk                                                 *
  175. *                                                                             *
  176. *   Function: This function performs the cleanup for the inking window and    *
  177. *             the associated memory.                                          *
  178. *                                                                             *
  179. * Parameters: hwndParent - is the window handle to the parent window. The     *
  180. *                          parent window will be the window containing the    *
  181. *                          image to be annotated.                             *
  182. *                                                                             *
  183. * Internal                                                                    *
  184. * References: EraseTimedInk - Cleans up display of window                     *
  185. *             PurgeTimedInk - Purge previous recording                        *
  186. *                                                                             *
  187. * Pen For OS2                                                                 *
  188. * References: None                                                            *
  189. *                                                                             *
  190. ******************************************************************************/
  191. BOOL APIENTRY DestroyTimedInk ( HWND hWnd )
  192. {
  193.    PMYWINDOWDATA  pMyWindowData;
  194.    HWND           hwndAudio;
  195.  
  196.    /***************************************************************************
  197.    * Get pointer to the window data.                                          *
  198.    ***************************************************************************/
  199.    pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
  200.  
  201.    /*****************************************************************
  202.    *  Close the audio dialog window along with this window.         *
  203.    *****************************************************************/
  204.    if (hwndAudio = WinWindowFromID(pMyWindowData->hwndParent,
  205.                                    IDD_AUDIO))
  206.    {
  207.       WinSendMsg(hwndAudio,
  208.                  WM_CLOSE,
  209.                  (MPARAM) NULL,
  210.                  (MPARAM) NULL);
  211.    };
  212.  
  213.    EraseTimedInk ( pMyWindowData );
  214.    PurgeTimedInk ( pMyWindowData->hwnd );
  215.    WinDestroyWindow ( pMyWindowData->hwnd );
  216.  
  217.    free ( pMyWindowData );
  218.    pMyWindowData = (PMYWINDOWDATA) NULL;
  219.    return ( IME_NO_ERROR );
  220. }
  221.  
  222. /******************************************************************************
  223. *                                                                             *
  224. * Subroutine: ScaleStrokeData                                                 *
  225. *                                                                             *
  226. *   Function: Converts stroke data in high resolution to screen resolution.   *
  227. *                                                                             *
  228. * Parameters: hWnd - Window handle for the inking window.                     *
  229. *                                                                             *
  230. * Internal                                                                    *
  231. * References: AppendStrokes - Appends new stroke to linked list pointer to by *
  232. *                             pStrokeHead                                     *
  233. *                                                                             *
  234. * Pen For OS2                                                                 *
  235. * References: WrtMapPointLong - Scales stroke data from one resolution to     *
  236. *                               another.                                      *
  237. *                                                                             *
  238. ******************************************************************************/
  239. BOOL ScaleStrokeData ( PMYWINDOWDATA pMyWindowData )
  240. {
  241.    PSTROKEDATA    pTempStrokeHead;
  242.    PSTROKEDATA    pTempCurrStroke;
  243.    PSTROKEDATA    pStrokeScaled;
  244.    RECTL          rcl;
  245.  
  246.    /***************************************************************************
  247.    * If the high resolution stroke data hasn't been scaled yet, then allocate *
  248.    * memory for the scaled stroke data.                                       *
  249.    ***************************************************************************/
  250.    if ( !pMyWindowData->pScaledHead )
  251.    {
  252.  
  253.       /************************************************************************
  254.       * Start off by saving the pointer to the high resolution stroke data,   *
  255.       * setting the pointer to the current stroke to convert, and then        *
  256.       * resetting the stroke head pointer to null.                            *
  257.       ************************************************************************/
  258.       pTempStrokeHead = pMyWindowData->pStrokeHead;
  259.       pTempCurrStroke = pMyWindowData->pStrokeHead;
  260.       pMyWindowData->pStrokeHead = NULL;
  261.  
  262.       /************************************************************************
  263.       * For every stroke in the high resolution stroke data linked list,      *
  264.       * allocate memory for the scaled stroke, copy high resolution stroke    *
  265.       * information to the scaled stroke structure, allocate memory for the   *
  266.       * scaled point information, and append new stroke to linked list.       *
  267.       ************************************************************************/
  268.       while ( pTempCurrStroke )
  269.       {
  270.          pStrokeScaled = (PSTROKEDATA) malloc (  sizeof(STROKEDATA) );
  271.          memcpy ( pStrokeScaled,
  272.                   pTempCurrStroke,
  273.                   sizeof(STROKEDATA) );
  274.          pStrokeScaled->pXY = (PPOINTL) malloc ( sizeof(POINTL) *
  275.                                                  pStrokeScaled->ulNumPoints );
  276.          AppendStrokes ( pMyWindowData, pStrokeScaled );
  277.          pTempCurrStroke = pTempCurrStroke->psdFwd;
  278.       };
  279.  
  280.       /************************************************************************
  281.       * pStrokeHead now points to a linked list of stroke headers for the     *
  282.       * scaled stroke data. Each stroke in this list has a pointer to an      *
  283.       * array of POINTL data structures, however the points in the array have *
  284.       * not yet been set. Save the pointer to the new linked list and restore *
  285.       * the pointer to the high resolution linked list.                       *
  286.       ************************************************************************/
  287.       pMyWindowData->pScaledHead = pMyWindowData->pStrokeHead;
  288.       pMyWindowData->pStrokeHead = pTempStrokeHead;
  289.    };
  290.  
  291.    /***************************************************************************
  292.    * For each stroke in the linked list, copy the high resolution point data, *
  293.    * and then scale it to the appropriate size.                               *
  294.    ***************************************************************************/
  295.    WinQueryWindowRect ( pMyWindowData->hwnd, &rcl );
  296.    pTempCurrStroke = pMyWindowData->pStrokeHead;
  297.    pStrokeScaled = pMyWindowData->pScaledHead;
  298.    while ( pTempCurrStroke )
  299.    {
  300.       memcpy ( pStrokeScaled->pXY,
  301.                pTempCurrStroke->pXY,
  302.                sizeof(POINTL) * pStrokeScaled->ulNumPoints );
  303.  
  304.       /************************************************************************
  305.       * WrtMapPointLong will convert the input points to a new resolution.    *
  306.       * The things to note here are that: 1) NULLHANDLE is used as the input  *
  307.       * window handle; and 2) the calculation for the extents. The NULLHANDLE *
  308.       * is used since we have already asked for the coordinates to be         *
  309.       * adjusted relative to the window at liftoff time. The documentation    *
  310.       * can be confusing on this point. If we were to provide the window      *
  311.       * for this window, then all of the points would be offset by the        *
  312.       * position of the window relative to the desktop origin. The extents    *
  313.       * are adjusted for changes in the window size. There is an inverse      *
  314.       * relationship between the extents and ink. Increase the extents and    *
  315.       * ink will be shrink. Decrease the extents and the ink will expand.     *
  316.       ************************************************************************/
  317.       WrtMapPointLong(NULLHANDLE,
  318.                       pStrokeScaled->pXY,
  319.                       MP_SCALE,
  320.                       ((pStrokeScaled->ulXExtent * pMyWindowData->OrgWindowSize.cx) / rcl.xRight),
  321.                       ((pStrokeScaled->ulYExtent * pMyWindowData->OrgWindowSize.cy) / rcl.yTop  ),
  322.                       0UL,
  323.                       0UL,
  324.                       pStrokeScaled->ulNumPoints);
  325.       pTempCurrStroke = pTempCurrStroke->psdFwd;
  326.       pStrokeScaled = pStrokeScaled->psdFwd;
  327.    };
  328.    return ( IME_NO_ERROR );
  329. }
  330.  
  331. /******************************************************************************
  332. *                                                                             *
  333. * Subroutine: PlayTimedInk                                                    *
  334. *                                                                             *
  335. *   Function: Initializes data structure for playback of a recording.         *
  336. *                                                                             *
  337. * Parameters: hWnd - Window handle for the inking window.                     *
  338. *                                                                             *
  339. * Internal                                                                    *
  340. * References: EraseTimedInk - Cleanup display of window                       *
  341. *             ScaleStrokeData - Scale data from high resolution               *
  342. *                                                                             *
  343. * Pen For OS2                                                                 *
  344. * References: None                                                            *
  345. *                                                                             *
  346. ******************************************************************************/
  347. BOOL APIENTRY PlayTimedInk ( HWND hWnd )
  348. {
  349.    PMYWINDOWDATA  pMyWindowData;
  350.  
  351.    /***************************************************************************
  352.    * Get pointer to the window data.                                          *
  353.    ***************************************************************************/
  354.    pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
  355.  
  356.    EraseTimedInk ( pMyWindowData );
  357.  
  358.    /***************************************************************************
  359.    * Convert high resolution stroke data to screen resolution                 *
  360.    ***************************************************************************/
  361.    if ( !pMyWindowData->pScaledHead )
  362.    {
  363.       ScaleStrokeData ( pMyWindowData );
  364.    };
  365.  
  366.    /***************************************************************************
  367.    * Prepare to playback the timed ink by setting current stroke to first     *
  368.    * stroke in linked list. If the first stroke exists set pointer to current *
  369.    * point and set the number of points remaining to be inked for the current *
  370.    * stroke.                                                                  *
  371.    ***************************************************************************/
  372.    pMyWindowData->pCurrStroke = pMyWindowData->pScaledHead;
  373.    if ( pMyWindowData->pCurrStroke != NULL )
  374.    {
  375.       pMyWindowData->NumPointsLeft  = pMyWindowData->pCurrStroke->ulNumPoints;
  376.       pMyWindowData->pCurrPoint     = pMyWindowData->pCurrStroke->pXY;
  377.    };
  378.  
  379.    /***************************************************************************
  380.    * Set flags to indicate current state.                                     *
  381.    ***************************************************************************/
  382.    pMyWindowData->fPlay    = TRUE;
  383.    pMyWindowData->fRecord  = FALSE;
  384.  
  385.    return ( IME_NO_ERROR );
  386. }
  387.  
  388.  
  389. /******************************************************************************
  390. *                                                                             *
  391. * Subroutine: RecordTimedInk                                                  *
  392. *                                                                             *
  393. *   Function: Initializes application in preparation to record timed ink.     *
  394. *                                                                             *
  395. * Parameters: hWnd - Window handle for inking window                          *
  396. *                                                                             *
  397. * Internal                                                                    *
  398. * References: EraseTimedInk - Cleanup display of window                       *
  399. *             PurgeTimedInk - Purge previous recording                        *
  400. *                                                                             *
  401. * Pen For OS2                                                                 *
  402. * References: None                                                            *
  403. *                                                                             *
  404. ******************************************************************************/
  405. BOOL APIENTRY RecordTimedInk ( HWND hWnd )
  406. {
  407.    PMYWINDOWDATA  pMyWindowData;
  408.    APIRET         rc;
  409.  
  410.    /***************************************************************************
  411.    * Get pointer to the window data.                                          *
  412.    ***************************************************************************/
  413.    pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
  414.  
  415.    /***************************************************************************
  416.    * Cleanup the window for the next recording.                               *
  417.    ***************************************************************************/
  418.    EraseTimedInk ( pMyWindowData );
  419.  
  420.    /***************************************************************************
  421.    * Free all of the old stroke data.                                         *
  422.    ***************************************************************************/
  423.    if ( pMyWindowData->pStrokeHead != NULL )
  424.    {
  425.       PurgeTimedInk ( hWnd );
  426.    }
  427.  
  428.    /***************************************************************************
  429.    * Set flags to indicate current state.                                     *
  430.    ***************************************************************************/
  431.    pMyWindowData->fPlay    = FALSE;
  432.    pMyWindowData->fRecord  = TRUE;
  433.  
  434.    return ( IME_NO_ERROR );
  435. }
  436.  
  437. /******************************************************************************
  438. *                                                                             *
  439. * Subroutine: EraseTimedInk                                                   *
  440. *                                                                             *
  441. *   Function: Removes ink from the transparent inking window.                 *
  442. *                                                                             *
  443. * Parameters: pMyWindowData - Pointer to windon specific information          *
  444. *                                                                             *
  445. * Internal                                                                    *
  446. * References: None                                                            *
  447. *                                                                             *
  448. * Pen For OS2                                                                 *
  449. * References: None                                                            *
  450. *                                                                             *
  451. ******************************************************************************/
  452. BOOL EraseTimedInk ( PMYWINDOWDATA pMyWindowData )
  453. {
  454.    RECTL rcl;
  455.  
  456.    /***************************************************************************
  457.    * Force the window to be repainted but without showing handwritten part.   *
  458.    ***************************************************************************/
  459.    GpiDeleteSegments ( pMyWindowData->hps, 1, pMyWindowData->NumSegments );
  460.    pMyWindowData->NumSegments = 0;
  461.  
  462.    WinQueryWindowRect ( pMyWindowData->hwndParent, &rcl );
  463.    WinInvalidateRect  ( pMyWindowData->hwndParent, &rcl, TRUE);
  464.  
  465.    /***************************************************************************
  466.    * Set flags to indicate current state.                                     *
  467.    ***************************************************************************/
  468.    pMyWindowData->fPlay    = FALSE;
  469.    pMyWindowData->fRecord  = FALSE;
  470.  
  471.    return ( IME_NO_ERROR );
  472. }
  473.  
  474. /******************************************************************************
  475. *                                                                             *
  476. * Subroutine: StopTimedInk                                                    *
  477. *                                                                             *
  478. *   Function: Stops recording of timed ink.                                   *
  479. *                                                                             *
  480. * Parameters: hWnd - Window handle for inking window                          *
  481. *                                                                             *
  482. * Internal                                                                    *
  483. * References: None                                                            *
  484. *                                                                             *
  485. * Pen For OS2                                                                 *
  486. * References: None                                                            *
  487. *                                                                             *
  488. ******************************************************************************/
  489. BOOL APIENTRY StopTimedInk ( HWND hWnd )
  490. {
  491.    RECTL          rcl;
  492.    PMYWINDOWDATA  pMyWindowData;
  493.  
  494.    /***************************************************************************
  495.    * Get pointer to the window data.                                          *
  496.    ***************************************************************************/
  497.    pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
  498.  
  499.    /***************************************************************************
  500.    * Set flags to indicate current state.                                     *
  501.    ***************************************************************************/
  502.    pMyWindowData->fPlay    = FALSE;
  503.    pMyWindowData->fRecord  = FALSE;
  504.  
  505.    return ( IME_NO_ERROR );
  506. }
  507.  
  508. /******************************************************************************
  509. *                                                                             *
  510. * Subroutine: PurgeTimedInk                                                   *
  511. *                                                                             *
  512. *   Function: Purges all strokes from memory.                                 *
  513. *                                                                             *
  514. * Parameters: hWnd - Window handle for inking window                          *
  515. *                                                                             *
  516. * Internal                                                                    *
  517. * References: None                                                            *
  518. *                                                                             *
  519. * Pen For OS2                                                                 *
  520. * References: None                                                            *
  521. *                                                                             *
  522. ******************************************************************************/
  523. BOOL APIENTRY PurgeTimedInk ( HWND hWnd )
  524. {
  525.    PMYWINDOWDATA  pMyWindowData;
  526.    PSTROKEDATA    pTempStroke;
  527.  
  528.    /***************************************************************************
  529.    * Get pointer to the window data.                                          *
  530.    ***************************************************************************/
  531.    pMyWindowData           = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
  532.  
  533.    /***************************************************************************
  534.    * Set flags to indicate current state.                                     *
  535.    ***************************************************************************/
  536.    pMyWindowData->fPlay    = FALSE;
  537.    pMyWindowData->fRecord  = FALSE;
  538.  
  539.    pMyWindowData->pCurrStroke = pMyWindowData->pStrokeHead;
  540.    while ( pMyWindowData->pCurrStroke != NULL )
  541.    {
  542.       pTempStroke = pMyWindowData->pCurrStroke->psdFwd;
  543.  
  544.       free ( pMyWindowData->pCurrStroke->pXY );
  545.       free ( pMyWindowData->pCurrStroke );
  546.  
  547.       pMyWindowData->pCurrStroke = pTempStroke;
  548.    };
  549.    pMyWindowData->pStrokeHead = NULL;
  550.  
  551.    pMyWindowData->pCurrStroke = pMyWindowData->pScaledHead;
  552.    while ( pMyWindowData->pCurrStroke != NULL )
  553.    {
  554.       pTempStroke = pMyWindowData->pCurrStroke->psdFwd;
  555.  
  556.       free ( pMyWindowData->pCurrStroke->pXY );
  557.       free ( pMyWindowData->pCurrStroke );
  558.  
  559.       pMyWindowData->pCurrStroke = pTempStroke;
  560.    };
  561.    pMyWindowData->pScaledHead = NULL;
  562.  
  563.    return ( IME_NO_ERROR );
  564. }
  565.  
  566.  
  567. /******************************************************************************
  568. *                                                                             *
  569. * Subroutine: AppendStrokes                                                   *
  570. *                                                                             *
  571. *   Function: Append a new stroke to the linked list of strokes for the       *
  572. *             current recording.
  573. *                                                                             *
  574. * Parameters: pMyWindowData - Pointer to window instance data                 *
  575. *             pStrokeData   - Pointer to the stroke data of the stroke to be  *
  576. *                             appended to the linked list of strokes          *
  577. *                                                                             *
  578. * Internal                                                                    *
  579. * References: None                                                            *
  580. *                                                                             *
  581. * Pen For OS2                                                                 *
  582. * References: None                                                            *
  583. *                                                                             *
  584. ******************************************************************************/
  585. BOOL AppendStrokes ( PMYWINDOWDATA pMyWindowData, PSTROKEDATA pStrokeData )
  586. {
  587.    /***************************************************************************
  588.    * If the stroke head pointer is null, then this is the first stroke in the *
  589.    * linked list of strokes.                                                  *
  590.    ***************************************************************************/
  591.    if ( pMyWindowData->pStrokeHead == NULL )
  592.    {
  593.       pMyWindowData->pStrokeHead = pStrokeData;
  594.       pMyWindowData->pCurrStroke = pStrokeData;
  595.       return ( IME_NO_ERROR );
  596.    };
  597.  
  598.    /***************************************************************************
  599.    * Otherwise, append the new stroke to the end of the linked list.          *
  600.    ***************************************************************************/
  601.    pMyWindowData->pCurrStroke->psdFwd = pStrokeData;
  602.    pStrokeData->psdBack = pMyWindowData->pCurrStroke;
  603.    pMyWindowData->pCurrStroke = pStrokeData;
  604.    return ( IME_NO_ERROR );
  605. }
  606.  
  607. /******************************************************************************
  608. *                                                                             *
  609. * Subroutine: InkTimedInk                                                     *
  610. *                                                                             *
  611. *   Function: This is a recursive routine that determines the strokes and     *
  612. *             points that need to be inked for this time interval.            *
  613. *                                                                             *
  614. * Parameters: hWnd - Window handle to inking window                           *
  615. *             ElapsedTime - This is the elapsed time ,in MMTIME units, from   *
  616. *                           the start of the recording                        *
  617. *                                                                             *
  618. * Internal                                                                    *
  619. * References: TimeToPoints - Convert a time duration to the number of points  *
  620. *                            to ink for the time duration                     *
  621. *             InkStroke    - Draw the stroke to the window                    *
  622. *             InkTimedInk  - Determine how much more to ink                   *
  623. *                                                                             *
  624. * Pen For OS2                                                                 *
  625. * References: None                                                            *
  626. *                                                                             *
  627. ******************************************************************************/
  628. BOOL APIENTRY InkTimedInk ( HWND hWnd, MMTIME ElapsedTime )
  629. {
  630.    ULONG             PointsToInk;
  631.    static   MMTIME   LastElapsedTime;
  632.    PMYWINDOWDATA     pMyWindowData;
  633.  
  634.    /***************************************************************************
  635.    * Get pointer to the window data.                                          *
  636.    ***************************************************************************/
  637.    pMyWindowData  = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
  638.  
  639.    /***************************************************************************
  640.    * If the pointer to the window data is null return FALSE to indicate an    *
  641.    * error condition.                                                         *
  642.    ***************************************************************************/
  643.    if ( pMyWindowData == NULL )
  644.       return ( IME_INVALID_POINTER );
  645.  
  646.    /***************************************************************************
  647.    * If the pointer to the current stroke is null then there are no more      *
  648.    * strokes remaining to be inked, so return TRUE to indicate things are ok. *
  649.    ***************************************************************************/
  650.    if ( pMyWindowData->pCurrStroke == NULL )
  651.    {
  652.       return ( IME_NO_ERROR );
  653.    };
  654.  
  655.    /***************************************************************************
  656.    * ulUser1 contains the start time for the stroke. If the current elapsed   *
  657.    * time is less than the start time for the current stroke,  then there are *
  658.    * aren't any points to ink for this time period. Save the elapsed time for *
  659.    * this call and TRUE to indicate things are ok.                            *
  660.    ***************************************************************************/
  661.    if ( ElapsedTime < pMyWindowData->pCurrStroke->ulUser1 )
  662.    {
  663.       LastElapsedTime = ElapsedTime;
  664.       return ( IME_NO_ERROR );
  665.    };
  666.  
  667.    /***************************************************************************
  668.    * ulUser2 contains the end time for the stroke. If the current elapsed     *
  669.    * time is greater than or equal to the end time for the current stroke,    *
  670.    * then the rest of the current stroke needs to be inked and perhaps more.  *
  671.    * Thus ink the rest of this stroke, set the last elapsed time, move to the *
  672.    * next stroke and make the recursive call to determine if more points need *
  673.    * to be inked, and return.                                                 *
  674.    ***************************************************************************/
  675.    if ( ElapsedTime >= pMyWindowData->pCurrStroke->ulUser2 )
  676.    {
  677.       InkStroke ( pMyWindowData, pMyWindowData->NumPointsLeft );
  678.       LastElapsedTime = pMyWindowData->pCurrStroke->ulUser2;
  679.       pMyWindowData->pCurrStroke = pMyWindowData->pCurrStroke->psdFwd;
  680.  
  681.       /************************************************************************
  682.       * If there are more strokes in the linked list then move to next stroke *
  683.       ************************************************************************/
  684.       if ( pMyWindowData->pCurrStroke != NULL )
  685.       {
  686.          pMyWindowData->NumPointsLeft = pMyWindowData->pCurrStroke->ulNumPoints;
  687.          pMyWindowData->pCurrPoint = pMyWindowData->pCurrStroke->pXY;
  688.          InkTimedInk ( hWnd, ElapsedTime );
  689.       };
  690.       return ( IME_NO_ERROR );
  691.    };
  692.  
  693.    /***************************************************************************
  694.    * If we get to this point then only a portion of the current stroke needs  *
  695.    * to be inked at this time. Determine how many points to ink, ink the      *
  696.    * points, set the elapsed time, and return.                                *
  697.    ***************************************************************************/
  698.    PointsToInk = TimeToPoints ( pMyWindowData, ElapsedTime - LastElapsedTime );
  699.    InkStroke ( pMyWindowData, PointsToInk );
  700.    LastElapsedTime = ElapsedTime;
  701.    return ( IME_NO_ERROR );
  702. }
  703.  
  704. /******************************************************************************
  705. *                                                                             *
  706. * Subroutine: TimeToPoints                                                    *
  707. *                                                                             *
  708. *   Function: This function calcualates and returns the number of points to   *
  709. *             be inked for a given amount of time.                            *
  710. *                                                                             *
  711. * Parameters: pMyWindowData - Pointer to window data                          *
  712. *             DeltaTime     - The amount of time that needs to be inked       *
  713. *                                                                             *
  714. * Internal                                                                    *
  715. * References: None                                                            *
  716. *                                                                             *
  717. * Pen For OS2                                                                 *
  718. * References: None                                                            *
  719. *                                                                             *
  720. ******************************************************************************/
  721. ULONG TimeToPoints ( PMYWINDOWDATA pMyWindowData, MMTIME DeltaTime )
  722. {
  723.    ULONG NumOfPoints;
  724.  
  725.    /***************************************************************************
  726.    * MMTIME is 1/3000 of a second. The sample rate is given in points per     *
  727.    * second. Thus the number of points to ink is calculated by:               *
  728.    *                                                                          *
  729.    *           1 SECOND                                NUM OF POINTS          *
  730.    *        ---------------- X DeltaTime MMTIMEUNITS X -------------          *
  731.    *        3000 MMTIMEUNITS                           SECOND                 *
  732.    *                                                                          *
  733.    * Once the estimate of the number of points has been made, check to see if *
  734.    * it exceeds the number of points remaining to be inked in the current     *
  735.    * stroke. Return the minimum of these two numbers.                         *
  736.    ***************************************************************************/
  737.    NumOfPoints = DeltaTime * pMyWindowData->pCurrStroke->ulSampleRate / 3000 ;
  738.    if ( pMyWindowData->NumPointsLeft < NumOfPoints )
  739.    {
  740.       NumOfPoints = pMyWindowData->NumPointsLeft;
  741.    };
  742.    return ( NumOfPoints );
  743. }
  744.  
  745.  
  746. /******************************************************************************
  747. *                                                                             *
  748. * Subroutine: InkStroke                                                       *
  749. *                                                                             *
  750. *   Function: This function draws the ink to the display during playback. It  *
  751. *             uses paths to draw 2 pel wide geometric lines. It then updates  *
  752. *             the number of points still waiting to be drawn, and moves the   *
  753. *             current point pointer to the next point to be drawn.            *
  754. *                                                                             *
  755. * Parameters: pMyWindowData - Pointer to window data                          *
  756. *             NumOfPoints   - Number of points to ink from the current stroke *
  757. *                                                                             *
  758. * Internal                                                                    *
  759. * References: None                                                            *
  760. *                                                                             *
  761. * Pen For OS2                                                                 *
  762. * References: None                                                            *
  763. *                                                                             *
  764. ******************************************************************************/
  765. BOOL InkStroke ( PMYWINDOWDATA pMyWindowData, ULONG NumOfPoints )
  766. {
  767.    /***************************************************************************
  768.    * If the current point is the first point in the stroke then the stroke    *
  769.    * not been inked yet. So move to the first point in the presentation space *
  770.    * in preparation for the polyline.                                         *
  771.    ***************************************************************************/
  772.    if ( pMyWindowData->pCurrPoint == pMyWindowData->pCurrStroke->pXY )
  773.    {
  774.       GpiOpenSegment ( pMyWindowData->hps, ++pMyWindowData->NumSegments );
  775.       GpiMove ( pMyWindowData->hps, pMyWindowData->pCurrPoint );
  776.    };
  777.  
  778.    /***************************************************************************
  779.    * Now draw the stroke on the screen                                        *
  780.    ***************************************************************************/
  781.    GpiBeginPath ( pMyWindowData->hps, 1 );
  782.    GpiPolyLine ( pMyWindowData->hps, NumOfPoints, pMyWindowData->pCurrPoint );
  783.    GpiEndPath ( pMyWindowData->hps );
  784.    GpiStrokePath ( pMyWindowData->hps, 1, 0 );
  785.  
  786.    /***************************************************************************
  787.    * Update the window data to indicate the number of points yet to be inked  *
  788.    * in the current stroke and move the current point pointer to the next     *
  789.    * next point to the last point inked.                                      *
  790.    ***************************************************************************/
  791.    pMyWindowData->NumPointsLeft -= NumOfPoints;
  792.    pMyWindowData->pCurrPoint    += NumOfPoints;
  793.  
  794.    /***************************************************************************
  795.    * If last point in stroke has been inked, then close the graphic segment.  *
  796.    ***************************************************************************/
  797.    if ( pMyWindowData->pCurrPoint == NULL )
  798.    {
  799.       GpiCloseSegment ( pMyWindowData->hps );
  800.    };
  801.  
  802.    return ( IME_NO_ERROR );
  803. }
  804.  
  805. /******************************************************************************
  806. *                                                                             *
  807. * Subroutine: InkWinProc                                                      *
  808. *                                                                             *
  809. *   Function: Window procedure for inking window. The inking window is a      *
  810. *             transparent window that we will be inking to during the capture *
  811. *             and playback of stroke data.                                    *
  812. *                                                                             *
  813. * Parameters: hWnd - Window handle                                            *
  814. *             msg  - Message Id                                               *
  815. *             mp1  - Message Parameter 1                                      *
  816. *             mp2  - Message Parameter 2                                      *
  817. *                                                                             *
  818. * Internal                                                                    *
  819. * References: AppendStrokes   - Append strokes to linked list                 *
  820. *             ScaleStrokeData - Scale strokes from high resolution            *
  821. *             PlayTimedInk    - Prepare to playback recording                 *
  822. *             InkTimedInk     - Draw ink to window                            *
  823. *             StopTimedInk    - Stop playback or recording                    *
  824. *                                                                             *
  825. * Pen For OS2                                                                 *
  826. * References: WrtQueryEventData - Get the event data from Pen for OS/2        *
  827. *             WrtQueryStrokeData - Get stroke data                            *
  828. *                                                                             *
  829. ******************************************************************************/
  830. MRESULT EXPENTRY InkWinProc ( HWND     hWnd,
  831.                               ULONG    msg,
  832.                               MRESULT  mp1,
  833.                               MRESULT  mp2 )
  834. {
  835.    SIZEL          PageSize;
  836.    PMYWINDOWDATA  pMyWindowData;
  837.    ULONG          buflen;
  838.    PSTROKEDATA    pStrokeData;
  839.    static MMTIME  TouchdownTime = 0;
  840.    static MMTIME  LiftoffTime   = 0;
  841.    APIRET         rc;
  842.    static USHORT  PointCounter = 0;
  843.    static POINTL  pPoint[8];
  844.    static BOOL    StrokeBufferOverrun = FALSE;
  845.    RECTL          rcl;
  846.    HPS            hpspaint;
  847.    WRTEVENTDATA   EventData;
  848.  
  849.    /***************************************************************************
  850.    * Get pointer to the window data.                                          *
  851.    ***************************************************************************/
  852.    pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
  853.    switch ( msg )
  854.    {
  855.       /************************************************************************
  856.       * Create this transparent window and setup the pMyWindowData. This      *
  857.       * structure is kept in reserved area.                                   *
  858.       ************************************************************************/
  859.       case  WM_CREATE:
  860.       {
  861.          /*********************************************************************
  862.          * Initialize window instance data                                    *
  863.          *********************************************************************/
  864.          pMyWindowData = (PMYWINDOWDATA) PVOIDFROMMP ( mp1 );
  865.          if ( !WinSetWindowPtr ( hWnd, 0, (PVOID) pMyWindowData ) )
  866.             return ( (MPARAM) TRUE );
  867.  
  868.          pMyWindowData->hwnd = hWnd;
  869.  
  870.          /*********************************************************************
  871.          * Create the presentation space for the window                       *
  872.          *********************************************************************/
  873.          pMyWindowData->hab = WinQueryAnchorBlock ( hWnd );
  874.          pMyWindowData->hdc = WinOpenWindowDC ( hWnd );
  875.          DevQueryCaps ( pMyWindowData->hdc, CAPS_WIDTH, 1L, &PageSize.cx );
  876.          DevQueryCaps ( pMyWindowData->hdc, CAPS_HEIGHT, 1L, &PageSize.cy );
  877.          pMyWindowData->hps = GpiCreatePS ( pMyWindowData->hab,
  878.                                             pMyWindowData->hdc,
  879.                                             &PageSize,
  880.                                             ( PU_PELS      |
  881.                                               GPIT_NORMAL  |
  882.                                               GPIF_LONG    |
  883.                                               GPIA_ASSOC   ) );
  884.          if ( pMyWindowData->hps == GPI_ERROR )
  885.          {
  886.             return ( (MPARAM) TRUE );
  887.          };
  888.  
  889.          /*********************************************************************
  890.          * Prepare the presentation space for drawing and retaining           *
  891.          * the graphic primatives                                             *
  892.          *********************************************************************/
  893.          GpiSetDrawingMode         ( pMyWindowData->hps, DM_DRAWANDRETAIN );
  894.          GpiSetDrawControl         ( pMyWindowData->hps,
  895.                                      DCTL_ERASE,
  896.                                      DCTL_OFF );
  897.          pMyWindowData->NumSegments = 0;
  898.  
  899.          /*********************************************************************
  900.          * Set initial presentation space attributes                          *
  901.          *********************************************************************/
  902.          pMyWindowData->CurrentColor = CLR_RED;
  903.          GpiSetColor ( pMyWindowData->hps,
  904.                        pMyWindowData->CurrentColor );
  905.          GpiSetLineWidthGeom ( pMyWindowData->hps, 2L );
  906.          GpiSetLineEnd ( pMyWindowData->hps, LINEEND_ROUND );
  907.          GpiSetLineJoin ( pMyWindowData->hps, LINEJOIN_ROUND );
  908.  
  909.          /*********************************************************************
  910.          * Set flags to initial state                                         *
  911.          *********************************************************************/
  912.          pMyWindowData->td      = FALSE;
  913.          pMyWindowData->fPlay   = FALSE;
  914.          pMyWindowData->fRecord = FALSE;
  915.  
  916.          /*********************************************************************
  917.          * Make the window visible and return                                 *
  918.          *********************************************************************/
  919.          WinShowWindow ( hWnd, TRUE );
  920.          return ( (MRESULT) FALSE );
  921.          break;
  922.       }
  923.  
  924.       /************************************************************************
  925.       * Get the start time of stroke, Capture mouse messages, move to         *
  926.       * the point where the pen touches the workpad to ink.                   *
  927.       ************************************************************************/
  928.       case WM_TOUCHDOWN:
  929.       {
  930.          /*********************************************************************
  931.          * Only process this message if we are in the process of creating     *
  932.          * a new recording.                                                   *
  933.          *********************************************************************/
  934.          if ( pMyWindowData->fRecord )
  935.          {
  936.             /******************************************************************
  937.             * Get the current time in MMTIME                                  *
  938.             ******************************************************************/
  939.             TouchdownTime = *(pCurrMMTime);
  940.             GpiOpenSegment  ( pMyWindowData->hps, ++pMyWindowData->NumSegments );
  941.             WinQueryWindowRect ( hWnd, &rcl );
  942.             pMyWindowData->OrgWindowSize.cx = rcl.xRight;
  943.             pMyWindowData->OrgWindowSize.cy = rcl.yTop;
  944.  
  945.             PointCounter = 0;
  946.  
  947.             pMyWindowData->td = TRUE;
  948.             WinSetCapture ( HWND_DESKTOP, hWnd );
  949.  
  950.             /******************************************************************
  951.             * Note that the (SHORT) cast is required in order to maintain     *
  952.             * sign.                                                           *
  953.             ******************************************************************/
  954.             pMyWindowData->points.x = (SHORT) SHORT1FROMMP ( mp1 );
  955.             pMyWindowData->points.y = (SHORT) SHORT2FROMMP ( mp1 );
  956.  
  957.             GpiMove ( pMyWindowData->hps, &pMyWindowData->points );
  958.  
  959.             /******************************************************************
  960.             * TDN_INFINTE: Inform Pen for OS/2 that the mouse button down     *
  961.             *              is not required.                                   *
  962.             * TDN_HIFREQ_MOUSEMOVE: Inform Pen for OS/2 to report the points  *
  963.             *              as mousemoves but at the sensor sample rate.       *
  964.             * TDN_NO_INK_STROKE: Inform Pen for OS/2 not to ink the points    *
  965.             *              since we will be doing our inking.                 *
  966.             ******************************************************************/
  967.             return ( (MRESULT) ( TDN_INFINITE         |
  968.                                  TDN_HIFREQ_MOUSEMOVE |
  969.                                  TDN_NO_INK_STROKE ));
  970.          };
  971.          break;
  972.       }
  973.  
  974.       /************************************************************************
  975.       *  For this message, the inking is done to show the stroke.             *
  976.       ************************************************************************/
  977.       case WM_MOUSEMOVE:
  978.       {
  979.          if ( pMyWindowData != NULL )
  980.          {
  981.             if ( pMyWindowData->td && pMyWindowData->fRecord )
  982.             {
  983.                /***************************************************************
  984.                * This release of Pen for OS/2 has a maximum limit to the size *
  985.                * of the stroke buffer. It is limited to 1024 points or eight  *
  986.                * seconds per stroke. If the maximum size of the stroke buffer *
  987.                * is reached, then inform the user via a tone.                 *
  988.                ***************************************************************/
  989.                if ( StrokeBufferOverrun )
  990.                {
  991.                   DosBeep ( 4000, 16 );
  992.                   return ( (MRESULT) TRUE );
  993.                };
  994.  
  995.                /***************************************************************
  996.                * Get the event data to see if the stroke buffer has been      *
  997.                * been filled.                                                 *
  998.                ***************************************************************/
  999.                EventData.cbStructSize = sizeof(EventData);
  1000.                WrtQueryEventData ( &EventData );
  1001.                if ( EventData.flEventStatus & WRT_BUFFER_OVERRUN )
  1002.                {
  1003.                   DosBeep ( 4000, 16 );
  1004.  
  1005.                   /******************************************************************
  1006.                   * Force the inking for all of the remaining points.               *
  1007.                   ******************************************************************/
  1008.                   GpiBeginPath ( pMyWindowData->hps, 1 );
  1009.                   GpiPolyLine ( pMyWindowData->hps, PointCounter, pPoint );
  1010.                   GpiEndPath ( pMyWindowData->hps );
  1011.                   GpiStrokePath ( pMyWindowData->hps, 1, 0 );
  1012.                   GpiCloseSegment ( pMyWindowData->hps );
  1013.                   StrokeBufferOverrun = TRUE;
  1014.                   return ( (MRESULT) TRUE );
  1015.                };
  1016.  
  1017.                /***************************************************************
  1018.                * Keep the (x,y) coordinate in a buffer of 8 entries.          *
  1019.                * Note that the (SHORT) cast is required in order to maintain  *
  1020.                * sign.                                                        *
  1021.                ***************************************************************/
  1022.                pPoint[PointCounter].x = (SHORT) SHORT1FROMMP( mp1 );
  1023.                pPoint[PointCounter].y = (SHORT) SHORT2FROMMP( mp1 );
  1024.                PointCounter++;
  1025.                if (PointCounter == 8)
  1026.                {
  1027.                   GpiBeginPath ( pMyWindowData->hps, 1 );
  1028.                   GpiPolyLine ( pMyWindowData->hps, 8L, pPoint );
  1029.                   GpiEndPath ( pMyWindowData->hps );
  1030.                   GpiStrokePath ( pMyWindowData->hps, 1, 0 );
  1031.                   PointCounter = 0;
  1032.                }
  1033.                return ( (MRESULT) TRUE );
  1034.             };
  1035.          };
  1036.          break;
  1037.       }
  1038.  
  1039.       /************************************************************************
  1040.       *  Stroke ends. Collect stroke end time, No more mouse message          *
  1041.       *  capture, Get the stroke data and Call AppendStrokes to adjust        *
  1042.       *  the stroke linked list in pMyWindowData.                             *
  1043.       ************************************************************************/
  1044.       case WM_LIFTOFF:
  1045.       {
  1046.          if ( pMyWindowData->td && pMyWindowData->fRecord )
  1047.          {
  1048.             /******************************************************************
  1049.             * Get the current time in MMTIME                                  *
  1050.             ******************************************************************/
  1051.             LiftoffTime = *(pCurrMMTime);
  1052.             WinSetCapture ( HWND_DESKTOP, NULLHANDLE );
  1053.             pMyWindowData->td = FALSE;
  1054.  
  1055.             /******************************************************************
  1056.             * If the buffer was overrun, then the points have already been    *
  1057.             * displayed.                                                      *
  1058.             ******************************************************************/
  1059.             if ( !StrokeBufferOverrun )
  1060.             {
  1061.                /******************************************************************
  1062.                * Force the inking for all of the remaining points.               *
  1063.                * Note that the (SHORT) cast is required in order to maintain     *
  1064.                * sign.                                                           *
  1065.                ******************************************************************/
  1066.                pPoint[PointCounter].x = (SHORT) SHORT1FROMMP( mp1 );
  1067.                pPoint[PointCounter].y = (SHORT) SHORT2FROMMP( mp1 );
  1068.                PointCounter++;
  1069.                GpiBeginPath ( pMyWindowData->hps, 1 );
  1070.                GpiPolyLine ( pMyWindowData->hps, PointCounter, pPoint );
  1071.                GpiEndPath ( pMyWindowData->hps );
  1072.                GpiStrokePath ( pMyWindowData->hps, 1, 0 );
  1073.                GpiCloseSegment ( pMyWindowData->hps );
  1074.             };
  1075.  
  1076.             /******************************************************************
  1077.             * Get the size of the stroke buffer.                              *
  1078.             ******************************************************************/
  1079.             buflen = 0;
  1080.             pStrokeData = NULL;
  1081.             rc = WrtQueryStrokeData ( (PBYTE) pStrokeData, &buflen, hWnd, QSD_SCALE, 0, 0, 0 );
  1082.             if ( rc )
  1083.               return (MRESULT) TRUE;
  1084.  
  1085.             if ( !buflen )
  1086.               return (MRESULT) TRUE;
  1087.  
  1088.             /******************************************************************
  1089.             * Allocate memory for the stroke buffer.                          *
  1090.             ******************************************************************/
  1091.             pStrokeData = (PSTROKEDATA) malloc ( buflen );
  1092.             if ( !pStrokeData )
  1093.             {
  1094.                return ( (MRESULT) TRUE );
  1095.             };
  1096.  
  1097.             /******************************************************************
  1098.             * Get the stroke data                                             *
  1099.             ******************************************************************/
  1100.             pStrokeData->cbStructSize = sizeof ( STROKEDATA );
  1101.             if ( WrtQueryStrokeData ( (PBYTE) pStrokeData,
  1102.                                       &buflen,
  1103.                                       pMyWindowData->hwnd,
  1104.                                       QSD_STANDARDIZED_RES,
  1105.                                       0,
  1106.                                       0,
  1107.                                       0 ) )
  1108.                return ( (MRESULT) LO_STROKE_PROCESSED );
  1109.  
  1110.             /******************************************************************
  1111.             * Append current stroke to linked list                            *
  1112.             ******************************************************************/
  1113.             AppendStrokes ( pMyWindowData, pStrokeData );
  1114.  
  1115.             /******************************************************************
  1116.             * Use existing structure entries for the stroke to hold the       *
  1117.             * touchdown and liftoff times for the current stroke              *
  1118.             ******************************************************************/
  1119.             pStrokeData->ulUser1 = TouchdownTime;
  1120.             pStrokeData->ulUser2 = LiftoffTime;
  1121.  
  1122.             StrokeBufferOverrun = FALSE;
  1123.  
  1124.             return ( (MRESULT) LO_STROKE_PROCESSED );
  1125.  
  1126.          }
  1127.          else
  1128.          {
  1129.             return ( (MRESULT) LO_DEFAULT );
  1130.          };
  1131.          return ( (MRESULT) FALSE );
  1132.       }
  1133.  
  1134.       /************************************************************************
  1135.       * Repaint the window, let the default window procedure handle.          *
  1136.       ************************************************************************/
  1137.       case  WM_PAINT:
  1138.       {
  1139.          hpspaint = WinBeginPaint  ( hWnd, pMyWindowData->hps, &rcl );
  1140.          GpiDrawChain ( hpspaint );
  1141.          WinEndPaint  ( hpspaint );
  1142.          return ( (MRESULT) TRUE );
  1143.       }
  1144.  
  1145.       /************************************************************************
  1146.       * Clean up before we close the window                                   *
  1147.       ************************************************************************/
  1148.       case WM_DESTROY:
  1149.       {
  1150.          GpiDestroyPS ( pMyWindowData->hps );
  1151.          return ( (MRESULT) FALSE );
  1152.       }
  1153.  
  1154.       /************************************************************************
  1155.       * When the parent window is resized, this window is resized. Scale the  *
  1156.       * data to the new size, and playback the ink into the window at the new *
  1157.       * scale.                                                                *
  1158.       ************************************************************************/
  1159.       case WM_SIZE:
  1160.       {
  1161.          if ( pMyWindowData != NULL )
  1162.          {
  1163.             if ( pMyWindowData->pStrokeHead )
  1164.             {
  1165.                WinShowWindow ( pMyWindowData->hwnd, FALSE );
  1166.                ScaleStrokeData ( pMyWindowData );
  1167.                PlayTimedInk ( pMyWindowData->hwnd );
  1168.                InkTimedInk ( pMyWindowData->hwnd, *(pCurrMMTime) );
  1169.                StopTimedInk ( pMyWindowData->hwnd );
  1170.                WinShowWindow ( pMyWindowData->hwnd, TRUE );
  1171.             }
  1172.             else
  1173.                EraseTimedInk ( pMyWindowData );
  1174.          };
  1175.          return ( (MRESULT) FALSE );
  1176.       }
  1177.  
  1178.       default:
  1179.          break;
  1180.    };
  1181.  
  1182.    return( (MRESULT) WinDefWindowProc ( hWnd, msg, mp1, mp2 )  );
  1183. };
  1184.