home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / clipview / clipview.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-05  |  21.8 KB  |  794 lines

  1. /*
  2.  * CLIPVIEW.C -- Clipboard Viewing application
  3.  * Created by Microsoft Corporation, 1989
  4.  *
  5.  * This program registers itself as the clipboard viewer, if no clipboard
  6.  * viewer exists.  Then, it intercepts WM_DRAWCLIPBOARD messages.
  7.  *
  8.  * This file contains the routines which handle the client/frame windows,
  9.  * the dialog routines, and the clipboard rendering code.
  10.  */
  11. #define    INCL_GPIBITMAPS
  12. #define    INCL_GPIMETAFILES
  13. #define INCL_WINATOM
  14. #define    INCL_WINCLIPBOARD
  15. #define    INCL_WINFRAMEMGR
  16. #define    INCL_WINLISTBOXES
  17. #define    INCL_WINMENUS
  18. #define    INCL_WINMLE
  19. #define    INCL_WINSCROLLBARS
  20. #define    INCL_WINSYS
  21. #define    INCL_WINWINDOWMGR
  22. #include <os2.h>
  23. #include <string.h>
  24. #include "clipview.h"
  25. /*
  26.  * Globals
  27.  */
  28. BITMAPINFOHEADER vbmp;            // Dimensions of current BITMAP
  29. BOOL    vfUpdate    = FALSE;    // Are we updating the clipboard?
  30. BOOL    vfViewBitmap    = FALSE;    // Are we currently viewing a...?
  31. HAB    vhab;                // Anchor block
  32. HDC    vhdcMemory;            // A memory DC for BitBlt-ing images
  33. HDC    vhdcWindow    = NULL;     // Client window DC
  34. HMQ    vhmqClip;            // Message queue
  35. HPS    vhpsMemory;            // A PS associated with vhdcMemory
  36. HWND    vhwndClient;            // Main client area
  37. HWND    vhwndClipFrame = NULL;        // Main frame window
  38. HWND    vhwndHSB    = NULL;     // Horizontal scroll bar
  39. HWND    vhwndMLE    = NULL;     // Handle to the MLE
  40. HWND    vhwndTitlebar    = NULL;     // Title-bar handle
  41. HWND    vhwndVSB    = NULL;     // Vertical scroll bar
  42. SHORT    vcMaxHSB;            // Maximum scroll range for HSB
  43. SHORT    vcMaxVSB;            // ...and for the VSB
  44. SHORT    vcUpdate    = -1;        // Counter for scroll bar updating
  45. USHORT    vausFormats[MAXFORMATS];    // All available formats
  46. USHORT    vcFmts;             // How many formats?
  47. USHORT    vusFormat;            // What is the current format?
  48. USHORT    vfsFmtInfo;            // Clipboard Format Information
  49. /*
  50.     Macros
  51. */
  52. #define LOADSTRING(id, sz) WinLoadString(vhab, (HMODULE) NULL, id, MAXLEN, sz)
  53. #define MESSAGE(sz) WinMessageBox(HWND_DESKTOP, vhwndClient, sz, NULL, 0, \
  54.             MB_OK | MB_ICONASTERISK | MB_SYSTEMMODAL);
  55. /*
  56.  * Main routine...initializes window and message queue
  57.  */
  58. int cdecl main( ) {
  59.     QMSG    qmsg;            /* Message queue */
  60.     ULONG   ctldata;            /* FCF_ flags */
  61.     BOOL    fViewer;            /* Does a viewer already exist? */
  62.     UCHAR   szAlready[MAXLEN];        /* Already extant... message */
  63.     UCHAR   szClassName[MAXLEN];    /* New class name */
  64.     /*
  65.     Start up our PM application
  66.     */
  67.     vhab = WinInitialize(0);
  68.     vhmqClip = WinCreateMsgQueue(vhab, 0);
  69.     /*
  70.     We create the client window first to try to avoid
  71.     synchronization problems.
  72.     */
  73.     LOADSTRING(IDS_CLIPCLASS, szClassName);
  74.     if (!WinRegisterClass( vhab, (PCH)szClassName, (PFNWP)ClipWndProc,
  75.         CS_SIZEREDRAW, 0))
  76.     return( 0 );
  77.     /*
  78.     Create the window (hidden)
  79.     */
  80.     ctldata = (FCF_STANDARD | FCF_HORZSCROLL | FCF_VERTSCROLL)
  81.                 & ~(FCF_ACCELTABLE);
  82.  
  83.     vhwndClipFrame = WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE, &ctldata,
  84.                      szClassName, "",
  85.                      WS_VISIBLE, (HMODULE) NULL, ID_RESOURCE,
  86.                      (PHWND) &vhwndClient );
  87.     /*
  88.     If there is no other clipboard viewer...
  89.     */
  90.     if (fViewer = !WinQueryClipbrdViewer(vhab, FALSE)) {
  91.     /*
  92.         ...we'll be the viewer.  Show the clipboard window.
  93.     */
  94.     WinSetClipbrdViewer(vhab, vhwndClient);
  95.     /*
  96.         Poll messages from event queue
  97.     */
  98.     while( WinGetMsg( vhab, (PQMSG)&qmsg, (HWND)NULL, 0, 0 ) )
  99.         WinDispatchMsg( vhab, (PQMSG)&qmsg );
  100.     /*
  101.         Stop being the clipboard viewer.
  102.     */
  103.     if (vhwndMLE)
  104.         WinDestroyWindow(vhwndMLE);
  105.     WinSetClipbrdViewer(vhab, NULL);
  106.     } else {
  107.     /*
  108.         ...otherwise, notify the user, then terminate.
  109.     */
  110.     LOADSTRING(IDS_ALREADY, szAlready);
  111.     MESSAGE(szAlready);
  112.     }
  113.     /*
  114.     Clean up
  115.     */
  116.     WinDestroyWindow( vhwndClipFrame );
  117.     WinDestroyMsgQueue( vhmqClip );
  118.     WinTerminate( vhab );
  119.  
  120.     return !fViewer;
  121. }
  122.  
  123. MRESULT CALLBACK ClipWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) {
  124. /*
  125.  
  126.  * This routine processes WM_COMMAND, WM_CREATE, WM_DRAWCLIPBOARD, WM_PAINT.
  127.  * Everything else is passed to the Default Window Procedure.
  128.  */
  129.     HPS        hpsWindow;
  130.     RECTL    rcl;
  131.     SWP     swp;
  132.     SIZEL    sizl;
  133.     UCHAR    szMessage[MAXLEN];
  134.  
  135.     switch (msg) {
  136.  
  137.     case WM_CREATE:
  138.         /*
  139.         Create a memory DC/PS to BitBlt BITMAPs around.
  140.         */
  141.         sizl.cx = sizl.cy = 0L;
  142.         vhdcMemory = DevOpenDC(vhab, OD_MEMORY, "*", 0L, NULL, NULL);
  143.         vhpsMemory = GpiCreatePS(vhab, vhdcMemory, &sizl,
  144.         GPIA_ASSOC | GPIF_DEFAULT | GPIT_MICRO | PU_PELS);
  145.         break;
  146.  
  147.     case WM_COMMAND:
  148.         switch (COMMANDMSG(&msg)->cmd) {
  149.         /*
  150.             About... dialog box
  151.         */
  152.         case IDM_ABOUT:
  153.             WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc,
  154.                   (HMODULE) NULL, IDD_ABOUT, NULL);
  155.             return 0;
  156.         /*
  157.             Render... dialog box
  158.         */
  159.         case IDM_RENDER:
  160.             WinDlgBox(HWND_DESKTOP, hwnd, RenderDlgProc,
  161.                   (HMODULE) NULL, IDD_RENDER, NULL);
  162.             return 0;
  163.         /*
  164.             Save... dialog box
  165.         */
  166.         case IDM_SAVE:
  167.             if (!SaveClipboard(hwnd, vusFormat)) {
  168.             LOADSTRING(IDS_NOTSAVED, szMessage);
  169.             MESSAGE(szMessage);
  170.             }
  171.             return 0;
  172.  
  173.         default: break;
  174.         }
  175.         break;
  176.  
  177.     case WM_ERASEBACKGROUND:
  178.         return (MRESULT) TRUE;
  179.         break;
  180.  
  181.     case WM_PAINT:
  182.         /* Open the presentation space */
  183.         hpsWindow = WinBeginPaint(hwnd, NULL, &rcl);
  184.  
  185.         /* Fill in the background */
  186.         WinFillRect(hpsWindow, &rcl, CLR_BACKGROUND);
  187.  
  188.         /* Paint in the clipboard */
  189.         UpdateScreen(hwnd, vusFormat);
  190.  
  191.         /* Finish painting */
  192.         WinEndPaint(hpsWindow);
  193.         break;
  194.  
  195.     case WM_DRAWCLIPBOARD:
  196.         /* Update the clipboard contents */
  197.         GetAllFormats();
  198.         vfUpdate = TRUE;
  199.         WinPostMsg(hwnd, WM_PAINT, 0L, 0L);
  200.         break;
  201.  
  202.     case WM_HSCROLL:
  203.         if (vfViewBitmap) {
  204.         /*
  205.             Handle the appropriate scrolling messages
  206.         */
  207.         DoScrolling(hwnd, TRUE, HIUSHORT(mp2));
  208.         } else
  209.         /*
  210.             If an ownerdraw format, let the owner handle it.
  211.         */
  212.         SendOwnerMsg(WM_HSCROLLCLIPBOARD, (MPARAM) hwnd, mp2);
  213.         break;
  214.  
  215.     case WM_VSCROLL:
  216.         if (vfViewBitmap) {
  217.         /*
  218.             Handle the appropriate scrolling messages
  219.         */
  220.         DoScrolling(hwnd, FALSE, HIUSHORT(mp2));
  221.         } else
  222.         /*
  223.             If an ownerdraw format, let the owner handle it.
  224.         */
  225.         SendOwnerMsg(WM_VSCROLLCLIPBOARD, (MPARAM) hwnd, mp2);
  226.         break;
  227.  
  228.     case WM_SIZE:
  229.         /*
  230.         If the MLE is processing a text selector,
  231.         tell it to resize itself.  If we have
  232.         owner-draw data, tell the clipboard owner.
  233.         If we have a BITMAP, readjust the scroll
  234.         bar ranges.
  235.         */
  236.         if (vhwndMLE) {
  237.         WinQueryWindowPos(vhwndMLE, &swp);
  238.         swp.cx = SHORT1FROMMP(mp2);
  239.         swp.cy = SHORT2FROMMP(mp2);
  240.         WinSetMultWindowPos(vhab, &swp, 1);
  241.         } else if (vfViewBitmap) {
  242.         WinQueryWindowPos(hwnd, &swp);
  243.         if ((vcMaxHSB = vbmp.cx - swp.cx) < 0)
  244.             vcMaxHSB = 0;
  245.         if ((vcMaxVSB = vbmp.cy - swp.cy) < 0)
  246.             vcMaxVSB = 0;
  247.         WinSendMsg(vhwndHSB, SBM_SETSCROLLBAR,
  248.             0L, MPFROM2SHORT(0, vcMaxHSB));
  249.         WinSendMsg(vhwndVSB, SBM_SETSCROLLBAR,
  250.             MPFROMSHORT(vcMaxVSB),
  251.             MPFROM2SHORT(0, vcMaxVSB));
  252.         } else {
  253.         rcl.xLeft = rcl.yBottom = 0L;
  254.         rcl.xLeft = (LONG) SHORT1FROMMP(mp2) - 1;
  255.         rcl.yTop  = (LONG) SHORT2FROMMP(mp2) - 1;
  256.         SendOwnerMsg(WM_SIZECLIPBOARD, (MPARAM) hwnd, &rcl);
  257.         }
  258.         break;
  259.  
  260.     default:
  261.         return WinDefWindowProc(hwnd, msg, mp1, mp2);
  262.         break;
  263.     }
  264.     return 0L;
  265. }
  266.  
  267. MRESULT CALLBACK RenderDlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
  268. {
  269. /*
  270.     Render... dialog procedure
  271. */
  272.     HWND    hwndListbox;        /* Listbox of possible formats */
  273.     UCHAR    szFmtName[MAXLEN];    /* Format name */
  274.     UCHAR    szMessage[MAXLEN];
  275.     USHORT    i;
  276.     USHORT    usFormat;        /* Format to render */
  277.     MRESULT    mrItem;         /* Which listbox item selected? */
  278.  
  279.     switch(msg) {
  280.  
  281.     case WM_INITDLG:
  282.         /*
  283.         Put all the possible formats into the listbox, and
  284.         select the first item by default.
  285.         */
  286.         hwndListbox = WinWindowFromID(hwndDlg, IDL_RENDER);
  287.         WinSendMsg(hwndListbox, LM_DELETEALL, 0L, 0L);
  288.         for (i = 0; i < vcFmts; i++) {
  289.         GetFormatName(vausFormats[i], szFmtName);
  290.         WinSendMsg(hwndListbox, LM_INSERTITEM,
  291.             MPFROMSHORT(LIT_END), MPFROMP((PVOID) szFmtName));
  292.         }
  293.         WinSendMsg(hwndListbox, LM_SELECTITEM, 0L, MPFROMSHORT(TRUE));
  294.         break;
  295.  
  296.     case WM_CONTROL:
  297.         /*
  298.         If the user makes a selection, quit!
  299.         */
  300.         if ((SHORT1FROMMP(mp1) == IDL_RENDER)
  301.         && (SHORT2FROMMP(mp1) == LN_ENTER))
  302.             WinPostMsg(hwndDlg, WM_COMMAND, MPFROMSHORT(DID_OK), 0L);
  303.         break;
  304.  
  305.     case WM_COMMAND:
  306.         switch(COMMANDMSG(&msg)->cmd) {
  307.         case DID_OK:
  308.             /*
  309.             Since the user chose a selection, try to render it.
  310.             */
  311.             hwndListbox = WinWindowFromID(hwndDlg, IDL_RENDER);
  312.             mrItem = WinSendMsg(hwndListbox, LM_QUERYSELECTION, 0L, 0L);
  313.             if (mrItem != (MRESULT) LIT_NONE) {
  314.             usFormat = vausFormats[SHORT1FROMMR(mrItem)];
  315.             if (usFormat != vusFormat) {
  316.                 /*
  317.                 If the clipboard format is not rendered,
  318.                 tell the user.
  319.                 */
  320.                 vfUpdate = TRUE;
  321.                 if (!UpdateScreen(vhwndClient, usFormat)) {
  322.                 LOADSTRING(IDS_NODISPLAY, szMessage);
  323.                 MESSAGE(szMessage);
  324.                 }
  325.             }
  326.             }
  327.  
  328.             /* fall through */
  329.  
  330.         case DID_CANCEL:
  331.             WinDismissDlg(hwndDlg, TRUE);
  332.  
  333.         default: break;
  334.         }
  335.     default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  336.     }
  337.     return FALSE;
  338. }
  339.  
  340. MRESULT CALLBACK AboutDlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
  341. {
  342. /*
  343.     About... dialog procedure
  344. */
  345.     switch(msg) {
  346.     case WM_COMMAND:
  347.         switch(COMMANDMSG(&msg)->cmd) {
  348.         case DID_OK: WinDismissDlg(hwndDlg, TRUE);
  349.         default: break;
  350.         }
  351.     default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  352.     }
  353.     return FALSE;
  354. }
  355.  
  356. VOID ReadSelector(HWND hwndMLE, PSZ pszText) {
  357. /*
  358.     Compute the length of the text selector, in bytes.
  359.     Allocate space, and copy the text selector into an MLE.
  360. */
  361.     IPT ipt;
  362.     ULONG ulcch = 0;
  363.     PSZ    pszCounter;
  364.  
  365.     pszCounter = pszText;
  366.     while (*pszCounter++) ulcch++;
  367.     WinSendMsg(hwndMLE, MLM_FORMAT, MPFROMSHORT(MLFIE_CFTEXT), 0L);
  368.     WinSendMsg(hwndMLE, MLM_SETIMPORTEXPORT, pszText, (MPARAM) ulcch);
  369.     WinSendMsg(hwndMLE, MLM_IMPORT, &ipt, (MPARAM) ulcch);
  370. }
  371.  
  372. VOID FixFrame(VOID) {
  373. /*
  374.     This routine tells the frame to update the scroll bars.
  375.  
  376.     First, make it so that the scroll bars cannot update themselves.
  377.     Let the frame update the controls.  Then, re-enable the scroll bars.
  378. */
  379.     if (!(vcUpdate--)) {
  380.     WinEnableWindowUpdate(vhwndHSB, FALSE);
  381.     WinEnableWindowUpdate(vhwndVSB, FALSE);
  382.     }
  383.  
  384.     WinSendMsg(vhwndClipFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_HORZSCROLL), 0L);
  385.     WinSendMsg(vhwndClipFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_VERTSCROLL), 0L);
  386.  
  387.     if (!(++vcUpdate)) {
  388.     WinEnableWindowUpdate(vhwndHSB, TRUE);
  389.     WinEnableWindowUpdate(vhwndVSB, TRUE);
  390.     }
  391. }
  392.  
  393. VOID NeedScrollBars(BOOL fNeed) {
  394. /*
  395.     This routine hides changes the scroll bar state to correspond with
  396.     fNeed, showing or hiding them as necessary.
  397. */
  398.     static BOOL fNeeded = TRUE;        /* The last scroll bar state */
  399.  
  400.     /*
  401.     Get the scroll bar handles, if we haven't already.
  402.     */
  403.     if (!vhwndHSB) {
  404.     vhwndHSB = WinWindowFromID(vhwndClipFrame, FID_HORZSCROLL);
  405.     vhwndVSB = WinWindowFromID(vhwndClipFrame, FID_VERTSCROLL);
  406.     }
  407.     /*
  408.     Case 1:  We need scroll bars, so enable them.
  409.     */
  410.     if (fNeed) {
  411.     if (!fNeeded) {
  412.         WinSetParent(vhwndHSB, vhwndClipFrame, TRUE);
  413.         WinSetParent(vhwndVSB, vhwndClipFrame, TRUE);
  414.         FixFrame();
  415.     }
  416.     /*
  417.     Case 2:  We don't need scroll bars, so hide them.
  418.     */
  419.     } else {
  420.     if (fNeeded) {
  421.         WinSetParent(vhwndHSB, HWND_OBJECT, TRUE);
  422.         WinSetParent(vhwndVSB, HWND_OBJECT, TRUE);
  423.         FixFrame();
  424.     }
  425.     }
  426.     /*
  427.     Save state for next invocation
  428.     */
  429.     fNeeded = fNeed;
  430. }
  431.  
  432. /*
  433.     RenderFormat()
  434.  
  435.     Input:        Clipboard format to render, and handle to client area
  436.     Side effects:    Renders the image in the client area
  437. */
  438. BOOL RenderFormat(HWND hwnd, USHORT usFormat) {
  439.     BOOL    fRendered = TRUE;
  440.     HMF        hmfCopy;
  441.     HPS     hpsWindow;
  442.     LONG    alOptions[8];
  443.     RECTL   rclWindow;
  444.     SIZEL   sizl;
  445.     SWP        swpWindow;
  446.     ULONG   hItem;
  447.     POINTL  aptl[3];
  448.     /*
  449.     Open the clipboard
  450.     */
  451.     if (!WinOpenClipbrd(vhab))
  452.     return FALSE;
  453.     /*
  454.     Open up the window DC and PS
  455.     */
  456.     if (!vhdcWindow)
  457.     vhdcWindow = WinOpenWindowDC(hwnd);
  458.  
  459.     sizl.cx = sizl.cy = 0L;
  460.     hpsWindow = GpiCreatePS(vhab, vhdcWindow, &sizl, GPIA_ASSOC | PU_ARBITRARY);
  461.     /*
  462.     Enable the scroll bars, if necessary.  This affects the size
  463.     of the client area.
  464.     */
  465.     if (vfUpdate)
  466.     NeedScrollBars( (vfViewBitmap =
  467.         (usFormat == CF_BITMAP) || (usFormat == CF_DSPBITMAP)) );
  468.  
  469.     WinQueryWindowRect(hwnd, &rclWindow);
  470.     /*
  471.     Get the clipboard data
  472.     */
  473.     WinQueryClipbrdFmtInfo(vhab, usFormat, &vfsFmtInfo);
  474.     if (!(hItem = WinQueryClipbrdData(vhab, usFormat))) {
  475.     fRendered = FALSE;
  476.     } else {
  477.       /*
  478.     Display the new format, as appropriate.
  479.       */
  480.       switch (usFormat) {
  481.     case CF_TEXT:
  482.     case CF_DSPTEXT:
  483.         if (vfUpdate) {
  484.         /*
  485.             Create a new MLE and read the text into it.
  486.         */
  487.         vhwndMLE = WinCreateWindow(hwnd, WC_MLE, "",
  488.             WS_VISIBLE | MLS_READONLY | MLS_HSCROLL | MLS_VSCROLL,
  489.             0, 0,
  490.             (SHORT) rclWindow.xRight, (SHORT) rclWindow.yTop,
  491.             hwnd, HWND_TOP, 0, NULL, NULL);
  492.  
  493.         ReadSelector(vhwndMLE, MAKEP((SEL) hItem, 0));
  494.         }
  495.         break;
  496.  
  497.     case CF_BITMAP:
  498.     case CF_DSPBITMAP:
  499.         if (vfUpdate) {
  500.         /*
  501.             Get the BITMAP dimensions, for scroll bar processing
  502.         */
  503.         if (GpiQueryBitmapParameters((HBITMAP) hItem, &vbmp)
  504.             != GPI_OK) {
  505.             return FALSE;
  506.         }
  507.         /*
  508.             Set the scroll bar ranges from 0 to vbmp.max - client.max
  509.         */
  510.         WinQueryWindowPos(hwnd, &swpWindow);
  511.  
  512.         if ((vcMaxHSB = vbmp.cx - swpWindow.cx) < 0)
  513.             vcMaxHSB = 0;
  514.         if ((vcMaxVSB = vbmp.cy - swpWindow.cy) < 0)
  515.             vcMaxVSB = 0;
  516.         WinSendMsg(vhwndHSB, SBM_SETSCROLLBAR,
  517.             0L, MPFROM2SHORT(0, vcMaxHSB));
  518.         WinSendMsg(vhwndVSB, SBM_SETSCROLLBAR,
  519.             MPFROMSHORT(vcMaxVSB),
  520.             MPFROM2SHORT(0, vcMaxVSB));
  521.         }
  522.         /*
  523.         Draw the BITMAP, based on the scroll bar settings.
  524.         */
  525.         GpiSetBitmap(vhpsMemory, (HBITMAP) hItem);
  526.  
  527.         aptl[0].x = rclWindow.xLeft;    /* Target bottom left */
  528.         aptl[0].y = rclWindow.yBottom;
  529.         aptl[1].x = rclWindow.xRight;    /* Target top right */
  530.         aptl[1].y = rclWindow.yTop;
  531.                         /* Source bottom left */
  532.         aptl[2].x = (LONG) WinSendMsg(vhwndHSB, SBM_QUERYPOS, 0L, 0L);
  533.         aptl[2].y = vcMaxVSB
  534.         - (LONG) WinSendMsg(vhwndVSB, SBM_QUERYPOS, 0L, 0L);
  535.  
  536.         GpiBitBlt(hpsWindow, vhpsMemory, 3L, aptl, ROP_SRCCOPY, 0L);
  537.         GpiSetBitmap(vhpsMemory, NULL);
  538.         break;
  539.  
  540.     case CF_METAFILE:
  541.     case CF_DSPMETAFILE:
  542.         /*
  543.         Set up the alOptions for displaying the metafile, and
  544.         let the system do the rest of the work.
  545.         */
  546.         alOptions[PMF_SEGBASE]        = 0L;
  547.         alOptions[PMF_LOADTYPE]        = LT_DEFAULT;
  548.         alOptions[PMF_RESOLVE]        = 0L;
  549.         alOptions[PMF_LCIDS]        = LC_LOADDISC;
  550.         alOptions[PMF_RESET]        = RES_DEFAULT;
  551.         alOptions[PMF_SUPPRESS]        = SUP_DEFAULT;
  552.         alOptions[PMF_COLORTABLES]        = CTAB_NOMODIFY;
  553.         alOptions[PMF_COLORREALIZABLE]  = CREA_DEFAULT;
  554.         hmfCopy = GpiCopyMetaFile((HMF) hItem);
  555.         GpiPlayMetaFile(hpsWindow, hmfCopy, 8L, alOptions, 0L, 0L, NULL);
  556.         break;
  557.  
  558.     case CF_EMPTY:
  559.         /*
  560.         Don't do anything.
  561.         */
  562.         break;
  563.  
  564.     default:
  565.         /*
  566.         If it's an owner-draw format that we can display...
  567.         ...try to get the owner to paint the clipboard.
  568.         (return if we were successful or not)
  569.         */
  570.         fRendered = SendOwnerMsg(WM_PAINTCLIPBOARD, MPFROMHWND(hwnd), 0L);
  571.         break;
  572.       }
  573.     }
  574.     /*
  575.     Tell everybody that the client area is valid now
  576.     */
  577.     WinValidateRect(hwnd, (PRECTL) NULL, FALSE);
  578.     /*
  579.     Clean up
  580.     */
  581.     GpiAssociate(hpsWindow, NULL);
  582.     GpiDestroyPS(hpsWindow);
  583.     WinCloseClipbrd(vhab);
  584.     return fRendered;
  585. }
  586.  
  587. BOOL UpdateScreen(HWND hwnd, USHORT usFormat) {
  588. /*
  589.     Render the format, change the title bar.
  590.     The title bar will look like:  "<appname> (<format>)"
  591. */
  592.     BOOL  fRendered = TRUE;
  593.     HPS   hpsWindow;
  594.     RECTL rcl;
  595.     UCHAR szFormat[MAXLEN];
  596.     UCHAR szTitle[MAXTITLELEN];
  597.  
  598.     if (vfUpdate) {
  599.     /* If the MLE exists, destroy it */
  600.     if (vhwndMLE) {
  601.         WinDestroyWindow(vhwndMLE);
  602.         vhwndMLE = NULL;
  603.     }
  604.  
  605.     /* Clear the client area */
  606.     WinQueryWindowRect(hwnd, &rcl);
  607.     WinInvalidateRect(hwnd, &rcl, FALSE);
  608.     hpsWindow = WinBeginPaint(hwnd, NULL, NULL);
  609.     WinFillRect(hpsWindow, &rcl, CLR_BACKGROUND);
  610.     WinEndPaint(hpsWindow);
  611.     }
  612.     if (usFormat)            // Check that usFormat != CF_EMPTY
  613.     fRendered = RenderFormat(hwnd, usFormat);
  614.     /*
  615.     Set the title bar appropriately
  616.     */
  617.     if (!vhwndTitlebar && vhwndClipFrame)
  618.     vhwndTitlebar = WinWindowFromID(vhwndClipFrame, FID_TITLEBAR);
  619.  
  620.     if (vhwndTitlebar) {
  621.     GetFormatName(usFormat, szFormat);
  622.     LOADSTRING(IDS_APPNAME, szTitle);
  623.     strcat(szTitle, "("); strcat(szTitle, szFormat); strcat(szTitle, ")");
  624.     WinSetWindowText(vhwndTitlebar, szTitle);
  625.     }
  626.     /*
  627.     Save the rendered format.
  628.     */
  629.     vusFormat = usFormat;
  630.     return fRendered;
  631. }
  632.  
  633. VOID GetAllFormats(VOID) {
  634.     USHORT usFormat;        // Temporary used when enumerating
  635.     /*
  636.     Put ourselves into a clean state
  637.     */
  638.     usFormat = vcFmts = 0;
  639.     /*
  640.     Cycle through the available clipboard formats
  641.     */
  642.     while (usFormat = WinEnumClipbrdFmts(vhab, usFormat)) {
  643.     vausFormats[vcFmts++] = usFormat;
  644.     }
  645.     /*
  646.     Set the current clipboard format to the first one, if possible
  647.     (in preparation for the WM_PAINT which will follow).
  648.     */
  649.     vusFormat = (vcFmts ? vausFormats[0] : CF_EMPTY);
  650. }
  651.  
  652. VOID GetFormatName(USHORT usFormat, UCHAR szFmtName[]) {
  653. /*
  654.     GetFormatName()
  655.  
  656.     This routine returns a format name in szFmtName which corresponds
  657.     to the format usFormat.  Basically, either we know the format, or
  658.     we get the name from the system atom table.  If we can't find it,
  659.     we set it to CF_UNKNOWN.
  660. */
  661.     switch (usFormat) {
  662.     /*
  663.         If we know the format, we can read it from the string table.
  664.     */
  665.     case CF_EMPTY:
  666.     case CF_TEXT:
  667.     case CF_DSPTEXT:
  668.     case CF_BITMAP:
  669.     case CF_DSPBITMAP:
  670.     case CF_METAFILE:
  671.     case CF_DSPMETAFILE:
  672.         LOADSTRING(usFormat, szFmtName);
  673.         break;
  674.  
  675.     default:
  676.         /*
  677.         Get the format name from the system atom table.
  678.         If not found, tag it as an unknown format.
  679.         */
  680.         if (!WinQueryAtomName(WinQuerySystemAtomTable(),
  681.            usFormat, szFmtName, MAXLEN))
  682.  
  683.         LOADSTRING(CF_UNKNOWN, szFmtName);
  684.  
  685.         break;
  686.     }
  687. }
  688.  
  689. BOOL SendOwnerMsg(USHORT msg, MPARAM mp1, MPARAM mp2) {
  690.     BOOL    rc;
  691.     HWND    hwndOwner;
  692.     /*
  693.     If we are an OWNERDISPLAY format,
  694.         lock the owner window, tell it to perform the operation, return
  695.     */
  696.     if ( rc = ( (vfsFmtInfo & CFI_OWNERDISPLAY)
  697.      && (hwndOwner = WinQueryClipbrdOwner(vhab, TRUE)) ) ) {
  698.  
  699.     WinSendMsg(hwndOwner, msg, mp1, mp2);
  700.     WinLockWindow(hwndOwner, FALSE);
  701.     }
  702.     return rc;
  703. }
  704.  
  705. BOOL DoScrolling(HWND hwnd, BOOL fHorz, USHORT sbCmd) {
  706. /*
  707.     This routine depends on the fact that the thumb cannot be set past the
  708.     range of the scroll bar.  Since this is handled in the system SBM_SETPOS
  709.     code already, we need not worry about it.
  710.  
  711.     We return TRUE if the scroll bar message is processed.
  712. */
  713.     HWND   hwndSB;        /* Scroll bar handle */
  714.     USHORT cpels;        /* Page length/width for PAGExxxx commands */
  715.     SWP    swp;            /* Dimensions of the client area */
  716.     USHORT usOld;        /* The current scroll bar position */
  717.     USHORT usNew;        /* The new scroll bar position */
  718.     /*
  719.     Set the scroll bar-specific parameters
  720.     */
  721.     WinQueryWindowPos(hwnd, &swp);
  722.     if (fHorz) {    /* Horizontal scroll bar */
  723.     hwndSB = vhwndHSB;
  724.     cpels = swp.cx;
  725.     } else {        /* Vertical scroll bar */
  726.     hwndSB = vhwndVSB;
  727.     cpels = swp.cy;
  728.     }
  729.     /*
  730.     Handle both scroll bars with one common routine
  731.  
  732.     Basically, the scroll bar has been set so that 
  733.     the thumb value corresponds to the offset that
  734.     the bitmap is drawn from.  So, to scroll by a
  735.     page, compute the number of pels of the page,
  736.     and move the thumb by that amount.
  737.  
  738.     This code is simplified by the fact that SB_SETPOS
  739.     will not allow the thumb to be set outside of the
  740.     range of the scroll bar, but will "stop" it at the
  741.     appropriate bound.
  742.     */
  743.     usOld = SHORT1FROMMR( WinSendMsg(hwndSB, SBM_QUERYPOS, 0L, 0L));
  744.  
  745.     switch (sbCmd) {
  746.     case SB_PAGERIGHT:    /* SB_PAGEDOWN */
  747.         WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld + cpels), 0L);
  748.         break;
  749.  
  750.     case SB_PAGELEFT:    /* SB_PAGEUP */
  751.         WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld - cpels), 0L);
  752.         break;
  753.  
  754.     case SB_LINERIGHT:    /* SB_LINEDOWN */
  755.         WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld + LINE), 0L);
  756.         break;
  757.  
  758.     case SB_LINELEFT:    /* SB_LINEUP */
  759.         WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld - LINE), 0L);
  760.         break;
  761.  
  762.     case SB_SLIDERPOSITION:
  763.         /*
  764.         It would be nice to be consistent with the other
  765.         SB_ cases, but the problem is that when this message
  766.         is sent, the position is *already* set to "usPosition".
  767.  
  768.         So, just invalidate the entire region, and hope that most
  769.         of these types of operations will be large scrolls.
  770.         */
  771.         // WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(LOUSHORT(mp2)), 0L);
  772.         WinInvalidateRect(hwnd, NULL, TRUE);
  773.         break;
  774.  
  775.     default:
  776.         return FALSE;
  777.     }
  778.     /*
  779.     Now, we find out where the new thumb position is,
  780.     scroll the window contents appropriately, and specify
  781.     SW_INVALIDATERGN so that the remainder will be
  782.     invalidated/repainted.
  783.     */
  784.     usNew = SHORT1FROMMR( WinSendMsg(hwndSB, SBM_QUERYPOS, 0L, 0L));
  785.     if (fHorz)
  786.     WinScrollWindow(hwnd, (SHORT) (usOld - usNew), 0, 
  787.         NULL, NULL, NULL, NULL, SW_INVALIDATERGN);
  788.     else
  789.     WinScrollWindow(hwnd, 0, (SHORT) (usNew - usOld),
  790.         NULL, NULL, NULL, NULL, SW_INVALIDATERGN);
  791.  
  792.     return TRUE;
  793. }
  794.