home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / focus.zip / FOCUS.C < prev    next >
Text File  |  1994-05-21  |  15KB  |  402 lines

  1. /*----------------------------------------------------------------------------*/
  2. /*  Superclass and Focus control example                                      */
  3. /*                                                                            */
  4. /*  Program brings up a dialog when "Run" is selected from the "File" menu.   */
  5. /*  The dialog contains two entryfields and a pushbutton, along with some     */
  6. /*  static text.  The entryfields will not allow a focus shift from one to    */
  7. /*  the other unless the entryfield contains the text "OK".  Focus change     */
  8. /*  IS always allowed to the pushbutton via the mouse.                        */
  9. /*                                                                            */
  10. /*  THIS PROGRAM RELIES ON <ONLY> DOCUMENTED MESSAGES AND BEHAVIOR.  In       */
  11. /*  addition to being an example of managing focus, it shows how you can      */
  12. /*  alter the behavior of a standard PM control.                              */
  13. /*                                                                            */
  14. /*  (c) 1994 Larry Morley                                                     */
  15. /*----------------------------------------------------------------------------*/
  16.  
  17. #define INCL_WIN
  18. #include <os2.h>
  19. #include <string.h>
  20. #include "focus.h"
  21.  
  22. /*----------------------------------------------------------------------------*/
  23. /* Defines and prototypes                                                     */
  24. /*----------------------------------------------------------------------------*/
  25.  
  26. #define YIELD_ATTEMPTS 100
  27.  
  28. int     main(VOID);
  29. PFNWP   SuperclassWindow
  30.    (PSZ szWinClass,PSZ szNewClass,PFNWP pNewWinProc,BOOL bNewClass);
  31. VOID    YieldCPU(USHORT nAttempts,ULONG ulDesiredMsg,HWND hwnd);
  32. MRESULT EXPENTRY NewEntryFieldProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2);
  33. MRESULT EXPENTRY ClientWinProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2);
  34. MRESULT EXPENTRY dlgExampleProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2);
  35.  
  36. /*----------------------------------------------------------------------------*/
  37. /* Global Variables                                                           */
  38. /*----------------------------------------------------------------------------*/
  39.  
  40. HWND  hFocus;                 /* The multiplex "who gets the focus" indicator */
  41.  
  42. HWND  hEntryField1;           /* Control window handles                       */
  43. HWND  hEntryField2;
  44.  
  45. PFNWP pfnOrigEntryFieldProc;  /* Pointer to the entry field control's         */
  46.                               /* original class window procedure.             */
  47.  
  48. /*----------------------------------------------------------------------------*/
  49.  
  50. HAB   hAB;
  51. HMQ   hMQ;
  52. HWND  hwndFrame;
  53. HWND  hwndClient;
  54. ULONG ulFrameFlags = FCF_TITLEBAR      | FCF_SYSMENU    |
  55.                      FCF_SIZEBORDER    | FCF_MINMAX     |
  56.                      FCF_SHELLPOSITION | FCF_TASKLIST   |
  57.                      FCF_MENU          | FCF_ICON;
  58.  
  59. /*----------------------------------------------------------------------------*/
  60.  
  61. PSZ   szClientClass          = "ClientWindowClass";
  62. PSZ   szEntryFieldSuperClass = "WCS_ENTRYFIELD";
  63.  
  64. /*----------------------------------------------------------------------------*/
  65. /* PFNWP SuperclassWindow                                                     */
  66. /*    (PSZ szWinClass,PSZ szNewClass,PFNWP pNewWinProc,BOOL bNewClass)        */
  67. /*                                                                            */
  68. /* This function registers a superclass of an existing class.                 */
  69. /*                                                                            */
  70. /*    The szWinClass parameter can be WC_FRAME, WC_BUTTON etc. -*or*- a       */
  71. /*    user-defined class like "MyWindowClass".                                */
  72. /*                                                                            */
  73. /*    The bNewClass variable should be TRUE if the class hasn't yet been      */
  74. /*    registered; false otherwise.                                            */
  75. /*                                                                            */
  76. /*    The function returns a pointer to the original class window procedure,  */
  77. /*    or NULL ((PFNWP)0) if an error occurs.                                  */
  78. /*----------------------------------------------------------------------------*/
  79.  
  80. PFNWP SuperclassWindow
  81.    (PSZ szWinClass,PSZ szNewClass,PFNWP pNewWinProc,BOOL bNewClass)
  82. {
  83.    CLASSINFO ci;
  84.    PFNWP     p;
  85.  
  86.    if(WinQueryClassInfo(hAB,szWinClass,&ci))
  87.    {
  88.       p = ci.pfnWindowProc;
  89.  
  90.       if (!WinRegisterClass(
  91.          hAB,
  92.          szNewClass,
  93.          pNewWinProc,
  94.          ci.flClassStyle & (~CS_PUBLIC),
  95.          ci.cbWindowData))
  96.             return (PFNWP)0;
  97.  
  98.       return p;
  99.    }
  100.    return (PFNWP)0;
  101. }
  102.  
  103. /*----------------------------------------------------------------------------*/
  104. /* VOID YieldCPU(USHORT nAttempts,ULONG ulDesiredMsg,HWND hwnd)               */
  105. /*                                                                            */
  106. /* This function essentially yields the CPU by checking for a particular      */
  107. /* messages, while checking for and dispatching other messages "n" times.     */
  108. /*----------------------------------------------------------------------------*/
  109.  
  110. VOID YieldCPU(USHORT nAttempts,ULONG ulDesiredMsg,HWND hwnd)
  111. {
  112.    QMSG         qmsg;
  113.  
  114.    while (nAttempts--)
  115.       if (WinPeekMsg(hAB,&qmsg,(HWND)0,(USHORT)0,(USHORT)0,PM_REMOVE))
  116.       {
  117.          if ((qmsg.msg == ulDesiredMsg) && (qmsg.hwnd == hwnd))
  118.             nAttempts = 0;
  119.          WinDispatchMsg(hAB,&qmsg);
  120.       }
  121.    return;
  122. }
  123.  
  124. /*----------------------------------------------------------------------------*/
  125. /*  New entryfield window procedure.  The entryfield will not give up the     */
  126. /*  focus unless it contains the text "OK".                                   */
  127. /*                                                                            */
  128. /*  A couple notes:                                                           */
  129. /*                                                                            */
  130. /*    WM_SETFOCUS does double duty.  It normally comes from PM, but I'm using */
  131. /*    it here for three reasons:                                              */
  132. /*                                                                            */
  133. /*       (1) With some controls, it makes the visual transition smoother.     */
  134. /*           It DOES NOT change the focus.  It just triggers the recapture    */
  135. /*           mechanism within the other control, and (sometimes) makes it     */
  136. /*           appear to have the focus before it does.                         */
  137. /*                                                                            */
  138. /*       (2) It allows the regain-the-focus, and the actual WM_SETFOCUS       */
  139. /*           to be handled in one "case".                                     */
  140. /*                                                                            */
  141. /*       (3) It's documented to be received when a control gains or loses     */
  142. /*           the focus; so, it's expected by the controls, and has an appr-   */
  143. /*           opriate priority.                                                */
  144. /*                                                                            */
  145. /*    And, this is only the beginning.  You'll probably want to, at some      */
  146. /*    point, get the type of the window, and make some specific adjustments;  */
  147. /*    i.e., you coud use WinQueryWindowUShort(hwnd,QWS_ID) to get the window  */
  148. /*    id and go from there..                                                  */
  149. /*                                                                            */
  150. /*----------------------------------------------------------------------------*/
  151.  
  152. MRESULT EXPENTRY NewEntryFieldProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
  153. {
  154.  
  155.    static BOOL bFocus    = FALSE;
  156.  
  157.    switch(msg)
  158.    {
  159.       case WM_SETFOCUS:
  160.       {
  161.          if (SHORT1FROMMP(mp2)) /* Gaining focus */
  162.          {
  163.             if (hFocus)
  164.             {
  165.                /*-------------------------------*/
  166.                /* Check to see if some other    */
  167.                /* window should have the focus. */
  168.                /*-------------------------------*/
  169.  
  170.                if(hFocus != hwnd)
  171.                {
  172.                   /*------------------------------*/
  173.                   /* Use WM_SETFOCUS to trigger   */
  174.                   /* the focus recovery procedure */
  175.                   /* in the other window and to   */
  176.                   /* try and make a visual change.*/
  177.                   /*------------------------------*/
  178.                   WinSendMsg(hFocus,msg,MPFROMHWND(hFocus),mp2);
  179.                   return (*pfnOrigEntryFieldProc)(hwnd,msg,mp1,mp2);
  180.                }
  181.             }
  182.  
  183.             /*------------------------------------*/
  184.             /* This handles the case of a SENT    */
  185.             /* WM_FOCUS, as well as a posted one. */
  186.             /*------------------------------------*/
  187.  
  188.             if (WinQueryFocus(HWND_DESKTOP) != hwnd)
  189.             {
  190.  
  191.                /*---------------------------*/
  192.                /* Actually call WinSetFocus */
  193.                /*---------------------------*/
  194.  
  195.                if (!bFocus)
  196.                   bFocus = WinSetFocus(HWND_DESKTOP,hwnd);
  197.  
  198.                /*---------------------------*/
  199.                /* Not always nescessary but */
  200.                /* won't hurt...             */
  201.                /*---------------------------*/
  202.  
  203.                YieldCPU(YIELD_ATTEMPTS,WM_SETFOCUS,hEntryField1);
  204.  
  205.                /*---------------------------*/
  206.                /* Retry if call failed.     */
  207.                /*---------------------------*/
  208.  
  209.                if (!bFocus)
  210.                   WinPostMsg(hwnd,msg,mp1,mp2);
  211.             }
  212.  
  213.             /*--------------------------------*/
  214.             /* Housekeeping so the mechanism  */
  215.             /* will work the next time around */
  216.             /*--------------------------------*/
  217.  
  218.             hFocus    = (HWND)0;
  219.             bFocus    = FALSE;
  220.             break;
  221.          }
  222.          else
  223.          {
  224.             /*------------------------------------------------------*/
  225.             /* This window is losing the focus.  Check the contents */
  226.             /* of the entryfield, and set the hFocus flag to "hwnd" */
  227.             /* if they're not correct.                              */
  228.             /*------------------------------------------------------*/
  229.  
  230.             CHAR scrap[128];
  231.  
  232.             WinQueryWindowText(hwnd,sizeof(scrap),scrap);
  233.  
  234.             /*--------------------------------*/
  235.             /* Set the hFocus flag based      */
  236.             /* on the text in the entryfield. */
  237.             /*--------------------------------*/
  238.  
  239.             if (strcmp(scrap,"OK"))
  240.                hFocus = hwnd;
  241.          }
  242.          break;
  243.       }
  244.    }
  245.  
  246.    /*-------------------------------------------*/
  247.    /* Call the original window procedure for    */
  248.    /* the control; NOT WinDefWindowProc().      */
  249.    /*-------------------------------------------*/
  250.  
  251.    return (*pfnOrigEntryFieldProc)(hwnd,msg,mp1,mp2);
  252. }
  253.  
  254. /*----------------------------------------------------------------------------*/
  255. /* A pretty standard main()...                                                */
  256. /*----------------------------------------------------------------------------*/
  257.  
  258. int main(VOID)
  259. {
  260.    QMSG qmsg;
  261.    int  rc;
  262.  
  263.    hAB = WinInitialize((USHORT)0);
  264.    hMQ = WinCreateMsgQueue(hAB,(SHORT)0);
  265.  
  266.    if (!(WinRegisterClass(
  267.       hAB,
  268.       szClientClass,
  269.       ClientWinProc,
  270.       CS_SIZEREDRAW,
  271.       (USHORT)0)))
  272.    {
  273.       rc = 1;
  274.       goto _pm_abterm;
  275.    }
  276.  
  277.    if (!(hwndFrame = WinCreateStdWindow(
  278.       HWND_DESKTOP,
  279.       0L,
  280.       &ulFrameFlags,
  281.       szClientClass,
  282.       (PSZ)0,
  283.       (ULONG)0L,
  284.       (HMODULE)0,
  285.       (USHORT)ID_MAINWINDOW,
  286.       &hwndClient)))
  287.    {
  288.       rc = 2;
  289.       goto _pm_abterm;
  290.    }
  291.  
  292.    WinSetWindowText(hwndFrame,"Superclass Sample");
  293.    WinShowWindow(hwndFrame,TRUE);
  294.  
  295.    while (WinGetMsg(hAB,&qmsg,(HWND)0,(USHORT)0,(USHORT)0))
  296.       WinDispatchMsg(hAB,&qmsg);
  297.  
  298. _pm_abterm:
  299.  
  300.    WinDestroyWindow(hwndFrame);
  301.    WinDestroyMsgQueue(hMQ);
  302.    WinTerminate(hAB);
  303.  
  304.    return rc;
  305. }
  306.  
  307. /*----------------------------------------------------------------------------*/
  308. /* Client window procedure; again, pretty standard                            */
  309. /*----------------------------------------------------------------------------*/
  310.  
  311. MRESULT EXPENTRY ClientWinProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
  312. {
  313.    switch (msg)
  314.    {
  315.       case WM_CREATE:
  316.       {
  317.          if (!(pfnOrigEntryFieldProc =
  318.             SuperclassWindow(
  319.                WC_ENTRYFIELD,
  320.                szEntryFieldSuperClass,
  321.                NewEntryFieldProc,
  322.                TRUE)))
  323.                   return (MRESULT)TRUE;
  324.          break;
  325.       }
  326.  
  327.       case WM_COMMAND:
  328.       {
  329.          switch (SHORT1FROMMP(mp1))
  330.          {
  331.             case IDM_FILE_RUN:
  332.             {
  333.                WinDlgBox(
  334.                   HWND_DESKTOP,
  335.                   hwnd,
  336.                   dlgExampleProc,
  337.                   (HMODULE)0,
  338.                   DLG_EXAMPLE,
  339.                   (PVOID)0);
  340.  
  341.                return (MRESULT) 0;
  342.             }
  343.  
  344.             case IDM_FILE_EXIT:
  345.             {
  346.                WinPostMsg(hwnd,WM_CLOSE,(MPARAM)0,(MPARAM)0);
  347.                return (MRESULT) 0;
  348.             }
  349.  
  350.             default:
  351.  
  352.                return WinDefWindowProc(hwnd,msg,mp1,mp2);
  353.          }
  354.       }
  355.  
  356.       case WM_PAINT:
  357.       {
  358.          HPS hPS;
  359.          hPS = WinBeginPaint(hwnd,(HPS)0,(PRECTL)0);
  360.          if (hPS)
  361.          {
  362.             GpiErase(hPS);
  363.             WinEndPaint(hPS);
  364.          }
  365.          break;
  366.       }
  367.  
  368.       default:
  369.  
  370.          return WinDefWindowProc(hwnd,msg,mp1,mp2);
  371.    }
  372.  
  373.    return (MRESULT)FALSE;
  374.  
  375. }
  376.  
  377. /*----------------------------------------------------------------------------*/
  378. /* Dialog that brings up the entryfields.  Straightforward stuff.             */
  379. /*----------------------------------------------------------------------------*/
  380.  
  381. MRESULT dlgExampleProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
  382. {
  383.  
  384.    switch (msg)
  385.    {
  386.       case WM_COMMAND:
  387.       {
  388.          switch (SHORT1FROMMP(mp1))
  389.          {
  390.             case DID_OK:
  391.  
  392.                WinDismissDlg(hwnd,TRUE);
  393.                return (MRESULT) 0;
  394.          }
  395.       }
  396.    }
  397.  
  398.    return WinDefDlgProc(hwnd,msg,mp1,mp2);
  399. }
  400.  
  401. /*----------------------------------------------------------------------------*/
  402.