home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cset21v1.zip / IBMCPP / WKFRAME / PMLINES / PMLINES.C next >
Text File  |  1993-02-28  |  28KB  |  615 lines

  1. #pragma strings( readonly )
  2.  
  3. /*+--------------------------------------------------------------------------+*/
  4. /*|                                                                          |*/
  5. /*| PROGRAM NAME: PMLINES                                                    |*/
  6. /*| -------------                                                            |*/
  7. /*|  A Simple OS/2 Presentation Manager Graphics Demonstration Program       |*/
  8. /*|                                                                          |*/
  9. /*| COPYRIGHT:                                                               |*/
  10. /*| ----------                                                               |*/
  11. /*|  Copyright (C) International Business Machines Corp., 1991,1992,1993.    |*/
  12. /*|                                                                          |*/
  13. /*| DISCLAIMER OF WARRANTIES:                                                |*/
  14. /*| -------------------------                                                |*/
  15. /*|  The following [enclosed] code is sample code created by IBM Corporation.|*/
  16. /*|  This sample code is not part of any standard IBM product and is provided|*/
  17. /*|  to you solely for the purpose of assisting you in the development of    |*/
  18. /*|  your applications.  The code is provided "AS IS", without warranty of   |*/
  19. /*|  any kind.  IBM shall not be liable for any damages arising out of your  |*/
  20. /*|  use of the sample code, even if they have been advised of the           |*/
  21. /*|  possibility of such damages.                                            |*/
  22. /*|                                                                          |*/
  23. /*| REVISION LEVEL: 1.0                                                      |*/
  24. /*| ---------------                                                          |*/
  25. /*|                                                                          |*/
  26. /*| WHAT THIS PROGRAM DOES:                                                  |*/
  27. /*| -----------------------                                                  |*/
  28. /*|  This program displays a standard window and then draws lines in the     |*/
  29. /*|  window.  Both the line and background colours change.                   |*/
  30. /*|                                                                          |*/
  31. /*| WHAT THIS PROGRAM DEMONSTRATES:                                          |*/
  32. /*| -------------------------------                                          |*/
  33. /*|  This program demonstrates how to create and display a standard window,  |*/
  34. /*|  use simple menus and dialog boxes, use a second thread for drawing,     |*/
  35. /*|  and displaying graphics using some basic GPI calls.                     |*/
  36. /*|                                                                          |*/
  37. /*| WHAT YOU NEED TO COMPILE THIS PROGRAM:                                   |*/
  38. /*| --------------------------------------                                   |*/
  39. /*|                                                                          |*/
  40. /*|  REQUIRED FILES:                                                         |*/
  41. /*|  ---------------                                                         |*/
  42. /*|                                                                          |*/
  43. /*|    PMLINES.C      - Source code                                          |*/
  44. /*|    PMLINES.MAK    - Make file for this program                           |*/
  45. /*|    PMLINES.DEF    - Module definition file                               |*/
  46. /*|    PMLINES.H      - Application header file                              |*/
  47. /*|    PMLINES.ICO    - Icon file                                            |*/
  48. /*|    PMLINES.RC     - Resource file                                        |*/
  49. /*|    PMLINES.DLG    - Dialog file                                          |*/
  50. /*|                                                                          |*/
  51. /*|    OS2.H          - Presentation Manager include file                    |*/
  52. /*|    STDLIB.H       - Standard library function declarations               |*/
  53. /*|    STRING.H       - String handling function declarations                |*/
  54. /*|                                                                          |*/
  55. /*|  REQUIRED LIBRARIES:                                                     |*/
  56. /*|  -------------------                                                     |*/
  57. /*|                                                                          |*/
  58. /*|    OS2386.LIB     - Presentation Manager/OS2 library                     |*/
  59. /*|    DDE4NBS.LIB    - Subsystem Development Library                        |*/
  60. /*|                                                                          |*/
  61. /*|  REQUIRED PROGRAMS:                                                      |*/
  62. /*|  ------------------                                                      |*/
  63. /*|                                                                          |*/
  64. /*|    IBM C Set/2 Compiler                                                  |*/
  65. /*|    IBM Linker                                                            |*/
  66. /*|    Resource Compiler                                                     |*/
  67. /*|                                                                          |*/
  68. /*| EXPECTED INPUT:                                                          |*/
  69. /*| ---------------                                                          |*/
  70. /*|                                                                          |*/
  71. /*| EXPECTED OUTPUT:                                                         |*/
  72. /*| ----------------                                                         |*/
  73. /*|                                                                          |*/
  74. /*+--------------------------------------------------------------------------+*/
  75.  
  76. /*+--------------------------------------------------------------------------+*/
  77. /*| System and library header files.                                         |*/
  78. /*+--------------------------------------------------------------------------+*/
  79.  
  80. #define INCL_NOCOMMON
  81. #define INCL_DOSPROCESS
  82. #define INCL_DOSSEMAPHORES
  83. #define INCL_DOSERRORS
  84. #define INCL_WINWINDOWMGR
  85. #define INCL_WINMESSAGEMGR
  86. #define INCL_WINFRAMEMGR
  87. #define INCL_WINDIALOGS
  88. #define INCL_WININPUT
  89. #define INCL_WINSWITCHLIST
  90. #define INCL_WINPROGRAMLIST
  91. #define INCL_GPICONTROL
  92. #define INCL_GPIPRIMITIVES
  93. #include <os2.h>
  94. #include <stdlib.h>
  95. #include <string.h>
  96.  
  97. /*+--------------------------------------------------------------------------+*/
  98. /*| Application header files.                                                |*/
  99. /*+--------------------------------------------------------------------------+*/
  100.  
  101. #include "pmlines.h"
  102.  
  103. /*+--------------------------------------------------------------------------+*/
  104. /*| Internal function prototypes.                                            |*/
  105. /*+--------------------------------------------------------------------------+*/
  106.  
  107. static void InitTitle( HAB, HWND, char * );
  108. static MRESULT EXPENTRY ClientWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 );
  109. static MRESULT EXPENTRY HelpDlgProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2 );
  110. static FNTHREAD DrawingThread;
  111. static void DisplayMessage( HAB, ULONG );
  112.  
  113. /*+--------------------------------------------------------------------------+*/
  114. /*| Static global variables and local constants.                             |*/
  115. /*+--------------------------------------------------------------------------+*/
  116.  
  117. #define WINDOW_CLASS   "My_Window"          /* window class name              */
  118. #define COLOUR_TBL_LEN 16                   /* number of colour table entries */
  119. #define MSG_BOX_ID     256                  /* error message box id           */
  120. #define STRING_LENGTH  128                  /* size of buffer used for strings*/
  121. #define STACK_SIZE     8192UL               /* stack size for second thread   */
  122.  
  123. static HWND   hwndClient = NULLHANDLE;      /* client window handle           */
  124. static HMQ    hmqThread2 = NULLHANDLE;      /* message queue handle for thread*/
  125. static POINTL ptl1;                         /* line start point               */
  126. static POINTL ptl2;                         /* line end point                 */
  127. static LONG   lFcolour = CLR_BLUE;          /* foreground (line) colour       */
  128. static LONG   lBcolour = CLR_DARKGRAY;      /* background colour              */
  129. static LONG   cxClient, cyClient;           /* client window X and Y size     */
  130. static LONG   fcolourcounter = 1L;          /* wait time to change line colour*/
  131. static TID    tidDrawing = 0UL;             /* drawing thread identifier      */
  132. static char   szAppName[ MAXNAMEL + 1 ];    /* application name string        */
  133.  
  134. /*+--------------------------------------------------------------------------+*/
  135. /*| Dummy argument parsing routine so that real one does not get linked in.  |*/
  136. /*+--------------------------------------------------------------------------+*/
  137.  
  138. void _setuparg( void ) {}
  139.  
  140. /*+--------------------------------------------------------------------------+*/
  141. /*| Main control procedure.                                                  |*/
  142. /*+--------------------------------------------------------------------------+*/
  143.  
  144. int main( void )
  145. {
  146.    HAB   hab = NULLHANDLE;                  /* PM anchor block handle         */
  147.    HMQ   hmq = NULLHANDLE;                  /* message queue handle           */
  148.    HWND  hwndFrame = NULLHANDLE;            /* frame window handle            */
  149.    ULONG flCreate = 0UL;                    /* window creation control flags  */
  150.    QMSG  qmsg;                              /* message from message queue     */
  151.    int   rc = 1;
  152.  
  153.    do
  154.    {
  155.       /* Initialize PM and create a message queue of default size.            */
  156.  
  157.       if ( ( hab = WinInitialize( 0UL ) ) == NULLHANDLE )
  158.          break;
  159.  
  160.       if ( ( hmq = WinCreateMsgQueue( hab, 0UL ) ) == NULLHANDLE )
  161.          break;
  162.  
  163.       /* Register client window class.                                        */
  164.  
  165.       if ( !WinRegisterClass( hab,          /* PM anchor block handle         */
  166.                               WINDOW_CLASS, /* window class name              */
  167.                           ClientWindowProc, /* address of window procedure    */
  168.                               CS_SIZEREDRAW,/* size changes cause redrawing   */
  169.                               0UL ) )       /* window data                    */
  170.       {
  171.          DisplayMessage( hab, IDS_NOREGISTER );
  172.          break;
  173.       }
  174.  
  175.       /* Create the standard windows but do not add the application to the    */
  176.       /* task manager list.                                                   */
  177.  
  178.       flCreate = FCF_STANDARD & ~FCF_TASKLIST;
  179.  
  180.       hwndFrame =
  181.          WinCreateStdWindow( HWND_DESKTOP,  /* make desktop window the parent */
  182.                              WS_VISIBLE,    /* frame window class style       */
  183.                              &flCreate,     /* frame control flags            */
  184.                              WINDOW_CLASS,  /* client window class name       */
  185.                              "",            /* title bar text                 */
  186.                              CS_SIZEREDRAW, /* client window class style      */
  187.                              0UL,           /* resource file handle - in EXE  */
  188.                              ID_WINDOW,     /* resources identifier           */
  189.                              &hwndClient ); /* client window handle           */
  190.       if ( hwndFrame == NULLHANDLE )
  191.       {
  192.          DisplayMessage( hab, IDS_NOSTDWINDOWS );
  193.          break;
  194.       }
  195.  
  196.       /* Initialize the window title and task switch list.                    */
  197.  
  198.       InitTitle( hab, hwndFrame, szAppName );
  199.  
  200.       /* Create the thread that will draw the lines.                          */
  201.       /* NOTE: _beginthread MUST be used if the thread contains CRT calls     */
  202.  
  203.       if ( DosCreateThread( &tidDrawing, DrawingThread, 0UL, 0UL, STACK_SIZE ) )
  204.       {
  205.          DisplayMessage( hab, IDS_NOTHREAD );
  206.          break;
  207.       }
  208.  
  209.       /* While the WM_QUIT message is not received, dispatch the message.     */
  210.       /* When the WM_QUIT message is received, WinGetMsg will return FALSE.   */
  211.  
  212.       while( WinGetMsg( hab, &qmsg, 0UL, 0UL, 0UL ) )
  213.          WinDispatchMsg( hab,               /* PM anchor block handle         */
  214.                          &qmsg );           /* pointer to message             */
  215.       rc = 0;
  216.  
  217.    }  while ( FALSE );
  218.  
  219.    /* Destroy the standard windows if they were created.                      */
  220.  
  221.    if ( hwndFrame != NULLHANDLE )
  222.       WinDestroyWindow( hwndFrame );        /* frame window handle            */
  223.  
  224.    /* Destroy the message queue and release the anchor block.                 */
  225.  
  226.    if ( hmq != NULLHANDLE )
  227.       WinDestroyMsgQueue( hmq );
  228.  
  229.    if ( hab != NULLHANDLE )
  230.       WinTerminate( hab );
  231.  
  232.    return rc;
  233. }
  234.  
  235. /*+--------------------------------------------------------------------------+*/
  236. /*| InitTitle - Initializes window title and task switch list.               |*/
  237. /*+--------------------------------------------------------------------------+*/
  238.  
  239. static void InitTitle( HAB hab, HWND hwnd, char *szTitle )
  240. {
  241.    SWCNTRL tSwcntrl;                        /* task switch structure          */
  242.  
  243.    /* Load the application name from the resources in the EXE.  Set the title */
  244.    /* bar text to this name.  Then add this application to the task manager   */
  245.    /* list with the loaded application name.                                  */
  246.  
  247.    WinLoadString( hab, 0UL, IDS_APPNAME, MAXNAMEL, szTitle );
  248.    WinSetWindowText( hwnd, szTitle );
  249.  
  250.    tSwcntrl.hwnd = hwnd;
  251.    tSwcntrl.hwndIcon = NULLHANDLE;
  252.    tSwcntrl.hprog = NULLHANDLE;
  253.    tSwcntrl.idProcess = 0;
  254.    tSwcntrl.idSession = 0;
  255.    tSwcntrl.uchVisibility = SWL_VISIBLE;
  256.    tSwcntrl.fbJump = SWL_JUMPABLE;
  257.    strcpy( tSwcntrl.szSwtitle, szTitle );
  258.    tSwcntrl.bProgType = PROG_PM;
  259.    WinAddSwitchEntry( &tSwcntrl );
  260.  
  261.    return;
  262. }
  263.  
  264. /*+--------------------------------------------------------------------------+*/
  265. /*| ClientWindowProc - Client window procedure.                              |*/
  266. /*+--------------------------------------------------------------------------+*/
  267.  
  268. static MRESULT EXPENTRY ClientWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  269. {
  270.    HPS   hps = NULLHANDLE;                  /* presentation space handle      */
  271.  
  272.    /* Process the message.                                                    */
  273.  
  274.    switch( msg )
  275.    {
  276.       case WM_CREATE:
  277.          /* The client window has been created but is not visible yet.        */
  278.          /* Initialize the window here.                                       */
  279.          break;
  280.  
  281.       case WM_CLOSE:
  282.          /* Tell the main procedure to terminate the message loop.            */
  283.  
  284.          WinPostMsg( hwnd, WM_QUIT, NULL, NULL );
  285.          break;
  286.  
  287.       case WM_PAINT:
  288.          /* Post a message to the second thread to make it repaint the        */
  289.          /* background.                                                       */
  290.  
  291.          hps = WinBeginPaint( hwnd, NULLHANDLE, NULL );
  292.  
  293.          WinPostQueueMsg( hmqThread2, WM_USER_REPAINT, 0UL, 0UL );
  294.  
  295.          WinEndPaint( hps );
  296.          break;
  297.  
  298.       case WM_COMMAND:
  299.          /* The user has chosen a menu item.  Process the selection           */
  300.          /* accordingly.                                                      */
  301.  
  302.          switch ( SHORT1FROMMP( mp1 ) )
  303.          {
  304.             case IDM_EXITPROG:
  305.                /* Post a close message.                                       */
  306.  
  307.                WinPostMsg( hwnd, WM_CLOSE, NULL, NULL );
  308.                break;
  309.  
  310.             case IDM_RESUME:
  311.                break;
  312.  
  313.             case IDM_HELPINSTRUCTIONS:
  314.                /* Display the help dialog box.                                */
  315.  
  316.                WinMessageBox( HWND_DESKTOP,      /* desktop is the parent     */
  317.                               hwnd,              /* owned by client window    */
  318.                               INSTRUCTIONS,      /* pointer to message text   */
  319.                               szAppName,         /* pointer to title text     */
  320.                               1UL,               /* message box identifier    */
  321.                               MB_OK | MB_INFORMATION | /* message box style   */
  322.                               MB_APPLMODAL | MB_MOVEABLE );
  323.  
  324.                /* Force a repaint.                                            */
  325.  
  326.                WinInvalidateRegion( hwnd, NULLHANDLE, FALSE );
  327.                break;
  328.  
  329.             case IDM_HELPABOUT:
  330.                /* Display the help dialog box.                                */
  331.  
  332.                WinDlgBox( HWND_DESKTOP,     /* make the desktop the parent    */
  333.                           hwnd,             /* owned by client window         */
  334.                           HelpDlgProc,      /* address of dialog procedure    */
  335.                           0UL,              /* module handle                  */
  336.                           IDD_HELP,         /* dialog identifier in resource  */
  337.                           NULL );           /* initialization data            */
  338.  
  339.                /* Force a repaint.                                            */
  340.  
  341.                WinInvalidateRegion( hwnd, NULLHANDLE, FALSE );
  342.                break;
  343.          }
  344.          break;
  345.  
  346.       case WM_SIZE:
  347.          /* Window is being resized so get new client window size and         */
  348.          /* recompute the end points for the lines.                           */
  349.  
  350.          cxClient = SHORT1FROMMP( mp2 );    /* Get new client window size     */
  351.          cyClient = SHORT2FROMMP( mp2 );
  352.          ptl1.x = cxClient / 2;             /* Set new points for lines based */
  353.          ptl1.y = cyClient / 2;             /* on the size of client window   */
  354.          ptl2.x = ptl1.x / 2;
  355.          ptl2.y = ptl1.y / 2;
  356.          break;
  357.  
  358.       case WM_BUTTON1DOWN:
  359.          /* The user has pushed mouse button 1 which means change the         */
  360.          /* foreground colour.                                                */
  361.  
  362.          /* Make sure that this window has the focus.                         */
  363.  
  364.          WinSetFocus( HWND_DESKTOP, hwnd );
  365.  
  366.          /* Reset foreground colour counter and increment foreground colour.  */
  367.  
  368.          fcolourcounter = 1;
  369.          lFcolour++;
  370.  
  371.          /* Make sure foreground and background colours are different.        */
  372.  
  373.          if ( lFcolour == lBcolour )
  374.             lFcolour++;
  375.  
  376.          /* Make sure the foregound colour does not exceed CLR_PALEGRAY.      */
  377.  
  378.          if ( lFcolour >= CLR_PALEGRAY )
  379.             lFcolour = CLR_BLUE;
  380.  
  381.          return ( MRESULT )TRUE;
  382.  
  383.       case WM_BUTTON1DBLCLK:
  384.          /* The user has double clicked mouse button 1 which means change     */
  385.          /* the background colour.                                            */
  386.  
  387.          /* Make sure that this window has the focus.                         */
  388.  
  389.          WinSetFocus( HWND_DESKTOP, hwnd );
  390.  
  391.          /* Increment the backgound colour but make sure the background       */
  392.          /* does not exceed CLR_PALEGRAY.                                     */
  393.  
  394.          if ( lBcolour == CLR_PALEGRAY )
  395.             lBcolour = CLR_BLUE;
  396.          else
  397.             ++lBcolour;
  398.  
  399.          /* Make sure foreground and background colours are different.        */
  400.  
  401.          if ( lFcolour == lBcolour )
  402.             lFcolour++;
  403.  
  404.          /* Make sure the foregound colour does not exceed CLR_PALEGRAY.      */
  405.  
  406.          if ( lFcolour >= CLR_PALEGRAY )
  407.             lFcolour = CLR_BLUE;
  408.  
  409.          /* Force the client window to repaint so that the background colour  */
  410.          /* is updated.                                                       */
  411.  
  412.          WinInvalidateRegion( hwnd, NULLHANDLE, FALSE );
  413.  
  414.          return ( MRESULT )TRUE;
  415.  
  416.       case WM_BUTTON2DOWN:
  417.          /* Make sure that this window has the focus.                         */
  418.  
  419.          WinSetFocus( HWND_DESKTOP, hwnd );
  420.  
  421.          /* Force the client window to repaint to clear the window.           */
  422.  
  423.          WinInvalidateRegion( hwnd, NULLHANDLE, FALSE );
  424.  
  425.          return ( MRESULT )TRUE;
  426.  
  427.       case WM_DESTROY:
  428.          /* The client window is being destroyed so tell the second thread to */
  429.          /* stop running.                                                     */
  430.  
  431.          WinPostQueueMsg( hmqThread2, WM_USER_END_THREAD, 0UL, 0UL );
  432.  
  433.          /* Wait for the drawing thread to terminate before returning.        */
  434.  
  435.          DosWaitThread( &tidDrawing, DCWW_WAIT );
  436.  
  437.          break;
  438.  
  439.       default:
  440.          /* For all other messages, let the default window procedure          */
  441.          /* process them.                                                     */
  442.  
  443.          return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  444.    }
  445.    return NULL;
  446. }
  447.  
  448. /*+--------------------------------------------------------------------------+*/
  449. /*| HelpDlgProc - Help Dialog Procedure                                      |*/
  450. /*+--------------------------------------------------------------------------+*/
  451.  
  452. static MRESULT EXPENTRY HelpDlgProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2 )
  453. {
  454.    switch( msg )
  455.    {
  456.       case WM_COMMAND:
  457.          switch( SHORT1FROMMP( mp1 ) )      /* Extract the command value      */
  458.          {
  459.             case DID_OK:                    /* The Enter pushbutton or key    */
  460.                WinDismissDlg( hwndDlg, TRUE );
  461.                break;
  462.  
  463.             default:
  464.                break;
  465.          }
  466.          break;
  467.  
  468.       default:
  469.          return WinDefDlgProc( hwndDlg, msg, mp1, mp2 );
  470.    }
  471.    return NULL;
  472. }
  473.  
  474. /*+--------------------------------------------------------------------------+*/
  475. /*| DrawingThread - Procedure that draws the lines in the client window.     |*/
  476. /*+--------------------------------------------------------------------------+*/
  477.  
  478. static void DrawingThread( ULONG ulThreadArg )
  479. {
  480.    /* Declare local variables.                                                */
  481.  
  482.    HAB   habThread2 = NULLHANDLE;           /* anchor block handle for thread */
  483.    HPS   hps = NULLHANDLE;                  /* presentation Space handle      */
  484.    LONG  delta1x = START_DELTA_X;           /* start point delta values       */
  485.    LONG  delta1y = START_DELTA_Y;
  486.    LONG  delta2x = END_DELTA_X;             /* end point delta values         */
  487.    LONG  delta2y = END_DELTA_Y;
  488.    RECTL rclClient;                         /* rectangle for client window    */
  489.    QMSG  qmsgThread2;                       /* message queue structure        */
  490.  
  491.    /* Change the priority class of this thread to idle class.                 */
  492.  
  493.    DosSetPriority( PRTYS_THREAD, PRTYC_IDLETIME, 0L, 0UL );
  494.  
  495.    /* Initialize thread to PM.                                                */
  496.  
  497.    habThread2 = WinInitialize( 0UL );
  498.    hmqThread2 = WinCreateMsgQueue( habThread2, 0UL );
  499.  
  500.    /* Get a presentation space.                                               */
  501.  
  502.    hps = WinGetPS( hwndClient );
  503.  
  504.    /* Run drawing thread.                                                     */
  505.  
  506.    qmsgThread2.msg = WM_USER_REPAINT;
  507.  
  508.    while ( qmsgThread2.msg != WM_USER_END_THREAD )
  509.    {
  510.       if ( qmsgThread2.msg == WM_USER_REPAINT )
  511.       {
  512.          WinQueryWindowRect( hwndClient, &rclClient );
  513.          WinFillRect( hps, &rclClient, lBcolour );
  514.       }
  515.       else
  516.       {
  517.          /* Increment the foreground colour if necessary.                     */
  518.  
  519.          if ( ++fcolourcounter > ( ( cxClient + cyClient ) >> 1 ) )
  520.          {
  521.             fcolourcounter = 1;                /* Reset fcolourcounter and    */
  522.             lFcolour++;                        /* increment foreground colour.*/
  523.  
  524.             /* Make sure foreground and background colours are different.     */
  525.  
  526.             if ( lFcolour == lBcolour )
  527.                lFcolour++;
  528.  
  529.             /* Make sure the foregound colour does not exceed CLR_PALEGRAY.   */
  530.  
  531.             if ( lFcolour >= CLR_PALEGRAY )
  532.                lFcolour = CLR_BLUE;
  533.          }
  534.  
  535.          /* Add deltas to the start and end points for a line.                */
  536.  
  537.          /* If the start point would be invalid then negate the delta.        */
  538.  
  539.          if ( ( ptl1.x + delta1x ) > cxClient )
  540.             delta1x = -delta1x;
  541.  
  542.          if ( ( ptl1.x + delta1x ) < 1 )
  543.             delta1x = -delta1x;
  544.  
  545.          if ( ( ptl1.y + delta1y ) > cyClient )
  546.             delta1y = -delta1y;
  547.  
  548.          if ( ( ptl1.y + delta1y ) < 1 )
  549.             delta1y = -delta1y;
  550.  
  551.          /* Add delta to start point.                                         */
  552.  
  553.          ptl1.x += delta1x;
  554.          ptl1.y += delta1y;
  555.  
  556.          /* If the end point would be invalid then negate the delta.          */
  557.  
  558.          if ( ( ptl2.x + delta2x ) > cxClient )
  559.             delta2x = -delta2x;
  560.          if ( ( ptl2.x + delta2x ) < 1 )
  561.             delta2x = -delta2x;
  562.          if ( ( ptl2.y + delta2y ) > cyClient )
  563.             delta2y = -delta2y;
  564.          if ( ( ptl2.y + delta2y ) < 1 )
  565.             delta2y = -delta2y;
  566.  
  567.          /* Add delta to end point.                                           */
  568.  
  569.          ptl2.x += delta2x;
  570.          ptl2.y += delta2y;
  571.  
  572.          /* Now draw the line.                                                */
  573.  
  574.          GpiSetColor( hps, lFcolour );
  575.          GpiMove( hps, &ptl1 );                /* Move to start point         */
  576.          GpiLine( hps, &ptl2 );                /* Draw new line               */
  577.       }
  578.  
  579.       /* Peek in the message queue to see if the main thread has posted a msg.*/
  580.  
  581.       WinPeekMsg( habThread2, &qmsgThread2, NULLHANDLE, 0UL, 0UL, PM_REMOVE );
  582.    }
  583.  
  584.    /* Clean up and terminate drawing thread.                                  */
  585.  
  586.    WinReleasePS( hps );
  587.    WinDestroyMsgQueue( hmqThread2 );
  588.    WinTerminate( habThread2 );
  589.    DosExit( EXIT_THREAD, 0UL );
  590. }
  591.  
  592. /*+--------------------------------------------------------------------------+*/
  593. /*| DisplayMessage - display an error message in a message box.              |*/
  594. /*+--------------------------------------------------------------------------+*/
  595.  
  596. static void DisplayMessage( HAB hab, ULONG ulStringNum )
  597. {
  598.    char szTemp[ STRING_LENGTH ];
  599.  
  600.    WinLoadString( hab, 0UL, ulStringNum, STRING_LENGTH, szTemp );
  601.  
  602.    WinAlarm( HWND_DESKTOP,                  /* desktop window handle          */
  603.              WA_ERROR );                    /* type of alarm                  */
  604.  
  605.    WinMessageBox( HWND_DESKTOP,             /* parent window handle           */
  606.                   HWND_DESKTOP,             /* owner window handle            */
  607.                   szTemp,                   /* pointer to message text        */
  608.                   szAppName,                /* pointer to title text          */
  609.                   MSG_BOX_ID,               /* message box identifier         */
  610.                   MB_OK | MB_ERROR |        /* message box style              */
  611.                   MB_SYSTEMMODAL );
  612.  
  613.    return;
  614. }
  615.