home *** CD-ROM | disk | FTP | other *** search
/ swCHIP 1991 January / swCHIP_95-1.bin / utility / gsview13 / src / gvwin.c < prev    next >
C/C++ Source or Header  |  1995-12-09  |  29KB  |  934 lines

  1. /* Copyright (C) 1993, 1994, Russell Lang.  All rights reserved.
  2.   
  3.   This file is part of GSview.
  4.   
  5.   This program is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the GSview Free Public Licence 
  9.   (the "Licence") for full details.
  10.   
  11.   Every copy of GSview must include a copy of the Licence, normally in a 
  12.   plain ASCII text file named LICENCE.  The Licence grants you the right 
  13.   to copy, modify and redistribute GSview, but only under certain conditions 
  14.   described in the Licence.  Among other things, the Licence requires that 
  15.   the copyright notice and this notice be preserved on all copies.
  16. */
  17.  
  18. /* gvwin.c */
  19. /* Main routines for Windows GSview */
  20. /* by Russell Lang */
  21. #include "gvwin.h"
  22.  
  23. char szAppName[MAXSTR];            /* application name - for title bar */
  24. char szExePath[MAXSTR];
  25. char szIniFile[MAXSTR];
  26. char szWait[MAXSTR];
  27. char szFindText[MAXSTR];
  28. char previous_filename[MAXSTR];
  29. const char szClassName[] = "gsview_class";
  30. const char szScratch[] = "gsview";    /* temporary filename prefix */
  31.  
  32. HWND hwndimg;            /* gsview main window */
  33. HWND hDlgModeless;        /* any modeless dialog box */
  34. HWND hwndtext;            /* gswin text window */
  35. HWND hwndimgchild;        /* gswin image child window */
  36. HINSTANCE phInstance;        /* instance of gsview */
  37. int bitmap_scrollx=0;        /* offset from bitmap to origin of child window */
  38. int bitmap_scrolly=0;
  39. PSFILE psfile;        /* Postscript file structure */
  40. PROG gsprog;        /* Ghostscript program structure */
  41. OPTIONS option;        /* GSview options (saved in INI file) */
  42. DISPLAY display;    /* Display parameters */
  43. PSDOC *doc;
  44. struct page_list_s page_list;    /*  page selection for print/extract */
  45.  
  46.  
  47. struct sound_s sound[NUMSOUND] = {
  48.     {"SoundOutputPage", IDS_SNDPAGE, ""},
  49.     {"SoundNoPage", IDS_SNDNOPAGE, BEEP},
  50.     {"SoundNoNumbering", IDS_SNDNONUMBER, ""},
  51.     {"SoundNotOpen", IDS_SNDNOTOPEN, ""},
  52.     {"SoundError", IDS_SNDERROR, BEEP},
  53.     {"SoundTimeout", IDS_SNDTIMEOUT, ""},
  54.     {"SoundStart", IDS_SNDSTART, ""},
  55.     {"SoundExit", IDS_SNDEXIT, ""},
  56. };
  57.  
  58. /* initialised in init.c */
  59. BOOL is_win31 = FALSE;        /* To allow selective use of win 3.1 features */
  60. BOOL is_winnt = FALSE;        /* To allow selective use of Windows NT features */
  61. BOOL is_win95 = FALSE;        /* To allow selective use of Windows 95 features */
  62. char szHelpName[MAXSTR];    /* buffer for building help filename */
  63. char szHelpTopic[MAXSTR];    /* topic for OFN_SHOWHELP */
  64. UINT help_message;        /* message sent by OFN_SHOWHELP */
  65. HMENU hmenu;            /* main menu */
  66. HACCEL haccel;            /* menu accelerators */
  67. HCURSOR hcWait;
  68. POINT img_offset;        /* offset to gswin child window */
  69. HFONT info_font;        /* font for info line */
  70. POINT info_file;        /* position of file information */
  71. POINT info_page;        /* position of page information */
  72. RECT  info_rect;        /* position and size of brief info area */
  73. RECT  info_coord;        /* position and size of coordinate information */
  74. RECT  button_rect;        /* position and size of button area */
  75.  
  76. BOOL prev_in_child;        /* true if cursor previously in gswin child window */
  77. BOOL waiting = FALSE;        /* true when 'wait' to be displayed in info area */
  78. int page_extra;            /* extra pages to skip */
  79. int page_skip = 5;        /* number of pages to skip in IDM_NEXTSKIP or IDM_PREVSKIP */
  80. BOOL changed_version = FALSE;    /* to warn user to update Ghostscript Command */
  81. BOOL zoom = FALSE;        /* true if display zoomed */
  82. BOOL debug = FALSE;        /* /D command line option used */
  83. HINSTANCE hlib_mmsystem;    /* DLL containing sndPlaySound function */
  84. FPSPS lpfnSndPlaySound;        /* pointer to sndPlaySound function if loaded */
  85.  
  86. /* timer used for open, close, display & print timeouts */
  87. BOOL bTimeout;            /* true if timeout occured */
  88. BOOL bTimerSet;            /* true if TIMER running */
  89. #define ID_MYTIMER 1
  90. UINT timeout_count;
  91.  
  92. /* document manipulation */
  93.  
  94. /* local functions */
  95. BOOL draw_button(DRAWITEMSTRUCT FAR *lpdis);
  96. BOOL in_child_client_area(void);
  97. BOOL in_client_area(void);
  98. BOOL in_info_area(void);
  99. void info_paint(HWND, HDC);
  100. void cursorpos_paint(HDC hdc);
  101. void gsview_close(void);
  102.  
  103.  
  104. int PASCAL 
  105. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
  106. {
  107.     MSG msg;
  108.  
  109.     /* copy the hInstance into a variable so it can be used */
  110.     phInstance = hInstance;
  111.  
  112.     LoadString(hInstance, IDS_TITLE, szAppName, sizeof(szAppName));
  113.     if (hPrevInstance) {
  114.         /* don't run more than one copy */
  115.         /* because we can't run more than one Ghostscript */
  116.         /* Win95 and WinNT always have hPrevInstance == 0 */
  117.         gsview_init0(lpszCmdLine);
  118.         return FALSE;
  119.     }
  120.  
  121.     gsview_init1(lpszCmdLine);
  122.     ShowWindow(hwndimg, cmdShow);
  123.     
  124.     while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
  125.         if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  126.             if (!TranslateAccelerator(hwndimg, haccel, &msg)) {
  127.             TranslateMessage(&msg);
  128.             DispatchMessage(&msg);
  129.             }
  130.         }
  131.     }
  132.  
  133.     play_sound(SOUND_EXIT);
  134.     gsview_close();
  135.      WinHelp(hwndimg,szHelpName,HELP_QUIT,(DWORD)NULL);
  136.     if (is_win31 && (hlib_mmsystem != (HINSTANCE)NULL))
  137.         FreeLibrary(hlib_mmsystem);
  138.     return 0;
  139. }
  140.  
  141.  
  142. /* parent overlapped window */
  143. LRESULT CALLBACK _export
  144. WndImgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  145. {
  146. RECT rect;
  147.  
  148.     if (message == WM_GSVIEW) {
  149.     switch(wParam) {
  150.         case HWND_TEXT:
  151.         /* lParam = handle to Ghostscript Borland EasyWin window */
  152.         hwndtext = (HWND)lParam;
  153.         break;
  154.         case HWND_IMGCHILD:
  155.         /* lParam = handle to Ghostscript image child window */
  156.         hwndimgchild = (HWND)lParam;
  157.         if (hwndimgchild && IsWindow(hwndimgchild)) {
  158.             SetClassCursor(hwndimgchild, LoadCursor((HINSTANCE)NULL, IDC_CROSS));
  159.             GetClientRect(hwnd, &rect);
  160.             SetWindowPos(hwndimgchild, (HWND)NULL, rect.left+img_offset.x, rect.top+img_offset.y,
  161.             rect.right-img_offset.x, rect.bottom-img_offset.y, 
  162.             SWP_NOZORDER | SWP_NOACTIVATE);
  163.         }
  164.         break;
  165.         case GSWIN_CLOSE:
  166.         /* something is closing gswin */
  167.         gsprog.hinst = (HINSTANCE)NULL;
  168.         gsprog.valid = FALSE;
  169.         hwndimgchild = (HWND)NULL;
  170.         hwndtext = (HWND)NULL;
  171.         bitmap_scrollx = bitmap_scrolly = 0;
  172.         display.page = FALSE;
  173.         display.saved = FALSE;
  174.         page_extra = 0;
  175.         pipeclose();
  176.         clear_timer();
  177.         info_wait(FALSE);
  178.         break;
  179.         case OUTPUT_PAGE:
  180.         /* showpage has just been called */
  181.         clear_timer();
  182.         play_sound(SOUND_PAGE);
  183.         if (IsIconic(hwndimg))    /* useless as an Icon so fix it */
  184.             ShowWindow(hwndimg, SW_SHOWNORMAL);
  185.         if ( !IsIconic(hwndimg) ) {  /* redraw child window */
  186.             if (hwndimgchild && IsWindow(hwndimgchild)) {
  187.             /* don't erase background - the bitmap will cover it anyway */
  188.             InvalidateRect(hwndimgchild, (LPRECT)NULL, FALSE);
  189.             UpdateWindow(hwndimgchild);
  190.             }
  191.         }
  192.         display.page = TRUE;
  193.         info_wait(FALSE);
  194.         if (page_extra) {
  195.             PostMessage(hwndimg, WM_COMMAND, IDM_SKIP, (LPARAM)0);
  196.         }
  197.         break;
  198.         case SYNC_OUTPUT:
  199.         /* time to redraw window */
  200.         if ( !IsIconic(hwndimg) ) {  /* redraw child window */
  201.             if (hwndimgchild && IsWindow(hwndimgchild)) {
  202.             /* don't erase background - the bitmap will cover it anyway */
  203.             InvalidateRect(hwndimgchild, (LPRECT)NULL, FALSE);
  204.             UpdateWindow(hwndimgchild);
  205.             }
  206.         }
  207.         break;
  208.         case SCROLL_POSITION:
  209.         /* User scrolled image window.  
  210.          * lParam = offsets to top left of image window
  211.          * we use these to display coordinates */
  212.         bitmap_scrollx = LOWORD(lParam);
  213.         bitmap_scrolly = HIWORD(lParam);
  214.         InvalidateRect(hwndimg, &info_coord, FALSE);
  215.         UpdateWindow(hwndimg);
  216.         break;
  217.         case PIPE_REQUEST:
  218.         load_string(IDS_WAITDRAW, szWait, sizeof(szWait));
  219.         info_wait(TRUE);
  220.         piperequest();
  221.         break;
  222.         case BEGIN:
  223.         case END:
  224.         /* do nothing at present */
  225.         /* we can figure out when we have reached EOF by inspecting */
  226.         /* the imitation pipe */
  227.         break;
  228.         default:
  229.         gserror(0, "Unknown Message", MB_ICONEXCLAMATION, -1);
  230.     }
  231.     return 0;
  232.     }
  233.     else if (message == help_message) {
  234.     WinHelp(hwndimg,szHelpName,HELP_KEY,(DWORD)szHelpTopic);
  235.     return 0;
  236.     } else
  237.     switch(message) {
  238.     case WM_CREATE:
  239.         hwndimg = hwnd;
  240.         gsview_create();
  241.         /* Enable Drag Drop */
  242.         if (is_win31)
  243.             DragAcceptFiles(hwnd, TRUE);
  244.         break;
  245.     case WM_DESTROY:
  246.         /* disable Drag Drop */
  247.         if (is_win31)
  248.             DragAcceptFiles(hwnd, FALSE);
  249.         gsview_close();
  250.         PostQuitMessage(0);
  251.         break;
  252.     case WM_ENDSESSION:
  253.         if (wParam)
  254.             gsview_close();
  255.         return 0;
  256.     case WM_TIMER:
  257.         if (wParam == ID_MYTIMER) {
  258.             timeout_count--;
  259.             if (timeout_count <= 0) {
  260.             clear_timer();
  261.             bTimeout = TRUE;
  262.             gserror(IDS_TIMEOUT, NULL, MB_ICONINFORMATION, SOUND_TIMEOUT);
  263.             info_wait(FALSE);
  264.             }
  265.         }
  266.         break;
  267.     case WM_DROPFILES:
  268.         if (is_win31) {
  269.             LPSTR szFile;
  270.                 HGLOBAL hglobal;
  271.             int i, cFiles, length;
  272.             HDROP hdrop = (HDROP)wParam;
  273. #ifdef __WIN32__
  274.             cFiles = DragQueryFile(hdrop, 0xffffffff, (LPSTR)NULL, 0);
  275. #else
  276.             cFiles = DragQueryFile(hdrop, 0xffff, (LPSTR)NULL, 0);
  277. #endif
  278.             for (i=0; i<cFiles; i++) {
  279.             length = DragQueryFile(hdrop, i, (LPSTR)NULL, 0);
  280.                 hglobal = GlobalAlloc(GHND | GMEM_SHARE, length+1);
  281.             if (hglobal) {
  282.                 szFile = GlobalLock(hglobal);
  283.                 DragQueryFile(hdrop, i, szFile, MAXSTR);
  284.                     GlobalUnlock(hglobal);
  285.                 /* it doesn't work if we call gsview_display directly */
  286.                 PostMessage(hwnd, WM_COMMAND, IDM_DROP, (LPARAM)hglobal);
  287.             }
  288.             }
  289.             DragFinish(hdrop);
  290.         }
  291.         break;
  292.     case WM_INITMENU:
  293.         if (hmenu == (HMENU)wParam) {
  294.             HMENU hmenuedit = GetSubMenu(hmenu,1);
  295.             if (hwndimgchild  && IsWindow(hwndimgchild))
  296.             EnableMenuItem(hmenu, IDM_COPYCLIP, MF_ENABLED);
  297.             else
  298.             EnableMenuItem(hmenu, IDM_COPYCLIP, MF_DISABLED | MF_GRAYED);
  299.             if (OpenClipboard(hwnd)) {
  300.             if (IsClipboardFormatAvailable(CF_DIB))
  301.                 EnableMenuItem(hmenu, IDM_PASTETO, MF_ENABLED);
  302.             else
  303.                 EnableMenuItem(hmenu, IDM_PASTETO, MF_DISABLED | MF_GRAYED);
  304.             if (IsClipboardFormatAvailable(CF_DIB) || 
  305.                 IsClipboardFormatAvailable(CF_BITMAP)) 
  306.                 EnableMenuItem(hmenu, IDM_CONVERT, MF_ENABLED);
  307.             else
  308.                 EnableMenuItem(hmenu, IDM_CONVERT, MF_DISABLED | MF_GRAYED);
  309.             /* Make EPS sub menu */
  310.             if ((IsClipboardFormatAvailable(CF_DIB) ||
  311.                  IsClipboardFormatAvailable(CF_BITMAP)) 
  312.                 && (doc != (PSDOC *)NULL) && doc->epsf)
  313.                 EnableMenuItem(hmenuedit, 5, MF_BYPOSITION | MF_ENABLED);
  314.             else
  315.                 EnableMenuItem(hmenuedit, 5, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
  316.             /* Extract EPS sub menu */
  317.             if ( (psfile.preview == IDS_EPST) || (psfile.preview == IDS_EPSW) )
  318.                 EnableMenuItem(hmenuedit, 6, MF_BYPOSITION | MF_ENABLED);
  319.             else
  320.                 EnableMenuItem(hmenuedit, 6, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
  321.             CloseClipboard();
  322.             }
  323.             return 0;
  324.         }
  325.         break;
  326.     case WM_COMMAND:
  327.         if (LOWORD(wParam) == IDM_DROP) {
  328.             LPSTR szFile;
  329.             char cmd[MAXSTR];
  330.             szFile = GlobalLock((HGLOBAL)lParam);
  331.             if (szFile && (lstrlen(szFile) < sizeof(cmd)))
  332.             lstrcpy(cmd, szFile);
  333.             else
  334.             cmd[0] = '\0';
  335. #ifdef NOTUSED
  336. #ifdef __WIN32__
  337.             hglobal = GlobalHandle((LPCVOID)lParam);
  338. #else
  339.             hglobal = (HGLOBAL)LOWORD(GlobalHandle(SELECTOROF(lParam)));
  340. #endif
  341. #endif
  342.             GlobalUnlock((HGLOBAL)lParam);
  343.             GlobalFree((HGLOBAL)lParam);
  344.             if ((cmd[0] == '-') || (cmd[0] == '/')) {
  345.             switch (toupper(cmd[1])) {
  346.                 case 'P':
  347.                       gsview_selectfile(cmd+2);
  348.                       gsview_print(FALSE);
  349.                   break;
  350.                 case 'F':
  351.                       gsview_selectfile(cmd+2);
  352.                       gsview_print(TRUE);
  353.                   break;
  354.                 case 'S':
  355.                   if (cmd[2] != ' ') {
  356.                 char *fname;
  357.                 /* skip over port name */
  358.                 for (fname=cmd+2; *fname && *fname!=' '; fname++)
  359.                   /* nothing */ ;
  360.                     /* skip blanks until file name */
  361.                     if (*fname) {
  362.                       *fname++ = '\0'; /* place null after port name */
  363.                       for (; *fname==' '; fname++)
  364.                         /* nothing */ ;
  365.                     }
  366.                     if (*fname) {
  367.                         /* found both filename and port */
  368.                         gsview_spool(fname, cmd+2);
  369.                         break;
  370.                     }
  371.                   }
  372.                       gsview_spool(cmd+2, (char *)NULL);
  373.                   break;
  374.                 default:
  375.                   gserror(IDS_BADCLI, cmd, MB_ICONEXCLAMATION, SOUND_ERROR);
  376.             }
  377.             }
  378.             else
  379.                 gsview_displayfile(cmd);
  380.         }
  381.         else {
  382.             if (GetNotification(wParam,lParam) != BN_DOUBLECLICKED) {
  383.             if (hDlgModeless) {
  384.                 play_sound(SOUND_ERROR);
  385.                 return 0;    /* obtaining Bounding Box so ignore commands */
  386.             }
  387.             if (waiting) {
  388.                 switch(LOWORD(wParam)) {
  389.                         case IDM_INFO:
  390.                         case IDM_SAVEDIR:
  391.                         case IDM_SETTINGS:
  392.                         case IDM_SAVESETTINGS:
  393.                         case IDM_SOUNDS:
  394.                         case IDM_HELPCONTENT:
  395.                         case IDM_HELPSEARCH:
  396.                         case IDM_ABOUT:
  397.                 case IDM_EXIT:
  398.                     /* these are safe to use when busy */
  399.                     break;
  400.                     default:
  401.                         play_sound(SOUND_ERROR);
  402.                         return 0;    /* Command not permitted now */
  403.                 }
  404.             }
  405.                 gsview_command(LOWORD(wParam));
  406.             }
  407.         }
  408.         /* if command resulted in an update to the display, do it */
  409.         if (display.do_endfile || display.do_resize || display.do_display) {
  410.             if (!gs_open())
  411.             return FALSE;
  412.             dfreopen();
  413.             do_output();
  414.             fflush(gsprog.input);
  415.             dfclose();
  416.             pipeflush();
  417.             display.busy = FALSE;
  418.             display.abort = FALSE;
  419.             display.do_endfile = FALSE;
  420.             display.do_resize = FALSE;
  421.             display.do_display = FALSE;
  422.         }
  423.         return 0;
  424.     case WM_KEYDOWN:
  425.     case WM_KEYUP:
  426.         /* pass on key presses so that child window scroll bars work */
  427.         if (hwndimgchild && IsWindow(hwndimgchild)) {
  428.             SendMessage(hwndimgchild, message, wParam, lParam);
  429.             return 0;
  430.         }
  431.         break;
  432.     case WM_SIZE:
  433.         /* make child window fill client area */
  434.         if (wParam != SIZE_MINIMIZED  && hwndimgchild !=(HWND)NULL && IsWindow(hwndimgchild))
  435.             SetWindowPos(hwndimgchild, (HWND)NULL, img_offset.x, img_offset.y,
  436.             LOWORD(lParam)-img_offset.x, HIWORD(lParam)-img_offset.y, 
  437.             SWP_NOZORDER | SWP_NOACTIVATE);
  438.         /* save window size for INIFILE */
  439.         if (wParam == SIZE_RESTORED) {
  440.             GetWindowRect(hwnd,&rect);
  441.             option.img_size.x = rect.right-rect.left;
  442.             option.img_size.y = rect.bottom-rect.top;
  443.         }
  444.         return 0;
  445.     case WM_MOVE:
  446.         /* save window position for INIFILE */
  447.         if (!IsIconic(hwnd) && !IsZoomed(hwnd)) {
  448.             GetWindowRect(hwnd,&rect);
  449.             option.img_origin.x = rect.left;
  450.             option.img_origin.y = rect.top;
  451.         }
  452.         return 0;
  453.     case WM_SETCURSOR:
  454.         /* if waiting, display hourglass cursor over our window */
  455.         if (waiting) {
  456.             if (hwndimgchild && IsWindow(hwndimgchild)) {
  457.             if (in_child_client_area() || in_info_area() || (LOWORD(lParam)==HTMENU)) {
  458.                 SetCursor(hcWait);
  459.                 return TRUE;
  460.                 }
  461.             }
  462.             else {
  463.                 SetCursor(hcWait);
  464.                 return TRUE;
  465.             }
  466.         }
  467.         /* track cursor and display coordinates if in child window */
  468.         if (hwndimgchild && IsWindow(hwndimgchild)) {
  469.             if (in_child_client_area() || prev_in_child) {
  470.             /* update coordinate info */
  471.             HFONT old_hfont;
  472.             HDC hdc = GetDC(hwnd);
  473.             if (info_font)
  474.                 old_hfont = SelectObject(hdc, info_font);
  475.             cursorpos_paint(hdc);
  476.             if (info_font)
  477.                 SelectObject(hdc, old_hfont);
  478.             ReleaseDC(hwnd, hdc);
  479.             }
  480.             prev_in_child = in_child_client_area();
  481.         }
  482.         break;
  483.     case WM_PARENTNOTIFY:
  484.         if (hDlgModeless && (wParam == WM_LBUTTONDOWN))
  485.             if (in_child_client_area())
  486.                 SendMessage(hDlgModeless, WM_COMMAND, BB_CLICK, lParam);
  487.         if (wParam == WM_RBUTTONDOWN) {
  488.             float x, y;
  489.             RECT rect;
  490.             GetWindowRect(hwndimgchild,&rect);
  491.             if (get_cursorpos(&x, &y)) {
  492.                 zoom = !zoom;
  493.                 display.zoom_xoffset = x;
  494.                 display.zoom_yoffset = y;
  495.             x = (bitmap_scrollx + (rect.right - rect.left)/2)*72.0/option.xdpi;
  496.             y = ((display.height-1) - (bitmap_scrolly + (rect.bottom - rect.top)/2))*72.0/option.ydpi;
  497.             transform_point(&x, &y);
  498.             x *= option.xdpi/72.0;
  499.             y *= option.ydpi/72.0;
  500.             display.zoom_xoffset -= (int)(x*72.0/option.zoom_xdpi);
  501.             display.zoom_yoffset -= (int)(y*72.0/option.zoom_ydpi);
  502.             }
  503.             else {
  504.                 zoom = FALSE;
  505.             }
  506.             PostMessage(hwndimg, WM_COMMAND, IDM_ZOOM, (LPARAM)0);
  507.         }
  508.         break;
  509.     case WM_ERASEBKGND:
  510.         /* when ghostscript window is valid */
  511.         /* don't bother erasing background */
  512.         if (hwndimgchild && IsWindow(hwndimgchild))
  513.             return 1;    /* say we have erased it */
  514.         break;
  515.     case WM_PAINT:
  516.         {
  517.         HDC hdc;
  518.         PAINTSTRUCT ps;
  519.         RECT chrect;
  520.         hdc = BeginPaint(hwnd, &ps);
  521.         /* draw info area at top */
  522.         info_paint(hwnd, hdc);
  523.         /* draw button background */
  524.         if (button_rect.right) {
  525.             GetClientRect(hwnd, &rect);
  526.             rect.top = button_rect.top;
  527.             rect.left = button_rect.left;
  528.             rect.right = button_rect.right;
  529.             FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  530.             SelectPen(hdc, GetStockObject(BLACK_PEN));
  531.             MoveTo(hdc, rect.right, rect.top);
  532.             LineTo(hdc, rect.right, rect.bottom);
  533.         }
  534.         /* fill area outside Ghostscript image client */
  535.         if (!option.fit_page && hwndimgchild && IsWindow(hwndimgchild)) {
  536.             GetClientRect(hwnd, &rect);
  537.             GetWindowRect(hwndimgchild, &chrect);
  538.             rect.top = info_rect.bottom+1;
  539.             rect.left = img_offset.x + chrect.right - chrect.left;
  540.             FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  541.             rect.left = button_rect.right+1;
  542.             rect.top = img_offset.y + chrect.bottom - chrect.top;
  543.             FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  544.         }
  545.         EndPaint(hwnd, &ps);
  546.         }
  547.         return 0;
  548.     case WM_MEASUREITEM:
  549.         return 1;
  550.     case WM_DRAWITEM:
  551.         return draw_button((DRAWITEMSTRUCT FAR *)lParam);
  552.     }
  553.     return DefWindowProc(hwnd, message, wParam, lParam);
  554. }
  555.  
  556. /* return TRUE if button drawn */
  557. BOOL
  558. draw_button(DRAWITEMSTRUCT FAR *lpdis)
  559. {
  560. HBRUSH hbrush;
  561. HPEN hpen_highlight, hpen_shadow, hpen_old;
  562. HDC hdc = lpdis->hDC;
  563. RECT rect;
  564. HICON hicon;
  565. HBITMAP hbitmap_old, hbitmap;
  566. BITMAP bm;
  567. int i;
  568. char buf[20];
  569.     rect = lpdis->rcItem;
  570.     if (lpdis->CtlType != ODT_BUTTON)
  571.         return FALSE;
  572.     switch (lpdis->itemAction) {
  573.         case ODA_DRAWENTIRE:
  574.         if ((hbitmap = LoadBitmap(phInstance,MAKEINTRESOURCE(lpdis->CtlID)))
  575.           != (HBITMAP)NULL) {
  576.             HDC hdcsrc = CreateCompatibleDC(hdc);
  577.             hbitmap_old = SelectObject(hdcsrc,hbitmap);
  578.             GetObject(hbitmap, sizeof(BITMAP),&bm);
  579.             if ( (rect.right-rect.left > bm.bmWidth) ||
  580.              (rect.bottom-rect.top > bm.bmHeight) ) {
  581.                 hbrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  582.                 FillRect(hdc, &rect, hbrush);
  583.                 DeleteBrush(hbrush);
  584.             }
  585.             BitBlt(hdc, (rect.left+rect.right-bm.bmWidth)/2,
  586.                (rect.top+rect.bottom-bm.bmHeight)/2,
  587.                bm.bmWidth,bm.bmHeight,hdcsrc,0,0,SRCCOPY);
  588.             SelectObject(hdcsrc,hbitmap_old);
  589.             DeleteObject(hbitmap);
  590.             DeleteDC(hdcsrc);
  591.         }
  592.         else {
  593.             hbrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  594.             FillRect(hdc, &rect, hbrush);
  595.             DeleteBrush(hbrush);
  596.             if ((i = LoadString(phInstance, lpdis->CtlID, buf, sizeof(buf)))
  597.                 != 0) {
  598. #ifdef __WIN32__
  599.             SIZE sz;
  600.             GetTextExtentPoint(hdc, buf, i, &sz);
  601.             SetBkMode(hdc, TRANSPARENT);
  602.             TextOut(hdc, (rect.left+rect.right-sz.cx)/2,
  603.                 (rect.top+rect.bottom-sz.cy)/2, buf, i);
  604. #else
  605.             DWORD dw = GetTextExtent(hdc, buf, i);
  606.             SetBkMode(hdc, TRANSPARENT);
  607.             TextOut(hdc, (rect.left+rect.right-LOWORD(dw))/2,
  608.                 (rect.top+rect.bottom-HIWORD(dw))/2, buf, i);
  609. #endif
  610.             }
  611.             else if ( (hicon = LoadIcon(phInstance, MAKEINTRESOURCE(lpdis->CtlID)))
  612.                 != (HICON)NULL )  {
  613.                 DrawIcon(hdc, (rect.left+rect.right-32)/2, 
  614.                     (rect.top+rect.bottom-32)/2, hicon);
  615.                 DestroyIcon(hicon);
  616.             }
  617.         }
  618.         hpen_old = SelectPen(hdc, GetStockObject(BLACK_PEN));
  619.         MoveTo(hdc, rect.left, rect.top);
  620.         LineTo(hdc, rect.right-1, rect.top);
  621.         LineTo(hdc, rect.right-1, rect.bottom-1);
  622.         LineTo(hdc, rect.left, rect.bottom-1);
  623.         LineTo(hdc, rect.left, rect.top-1);
  624.         SelectPen(hdc, hpen_old);
  625.         /* fall thru */
  626.         case ODA_FOCUS:
  627.         case ODA_SELECT:
  628.         if (lpdis->itemState & ODS_SELECTED) {
  629.             hpen_highlight = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
  630.             hpen_shadow = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE));
  631.         }
  632.         else {
  633.             hpen_highlight = CreatePen(PS_SOLID, 1, is_win31 ? GetSysColor(COLOR_BTNHIGHLIGHT) : RGB(255,255,255));
  634.             hpen_shadow = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
  635.         }
  636.         hpen_old = SelectPen(hdc, hpen_highlight);
  637.         MoveTo(hdc, rect.left+1, rect.bottom-3);
  638.         LineTo(hdc, rect.left+1, rect.top+1);
  639.         LineTo(hdc, rect.right-2, rect.top+1);
  640.         MoveTo(hdc, rect.right-3, rect.top+2);
  641.         LineTo(hdc, rect.left+2, rect.top+2);
  642.         LineTo(hdc, rect.left+2, rect.bottom-4);
  643.         SelectPen(hdc, hpen_shadow);
  644.         MoveTo(hdc, rect.left+1, rect.bottom-2);
  645.         LineTo(hdc, rect.right-2, rect.bottom-2);
  646.         LineTo(hdc, rect.right-2, rect.top+1);
  647.         MoveTo(hdc, rect.right-3, rect.top+2);
  648.         LineTo(hdc, rect.right-3, rect.bottom-3);
  649.         LineTo(hdc, rect.left+2, rect.bottom-3);
  650.         SelectPen(hdc, hpen_old);
  651.         DeleteObject(hpen_highlight);
  652.         DeleteObject(hpen_shadow);
  653.             return TRUE;
  654.     }
  655.     return FALSE;
  656. }
  657.  
  658. /* returns true if cursor in client area of Ghostscript image window */
  659. BOOL
  660. in_child_client_area()
  661. {
  662. RECT rect;
  663. POINT pt;
  664. HWND hwnd;
  665.         GetCursorPos(&pt);
  666.     hwnd = WindowFromPoint(pt);
  667.     if ((hwnd != hwndimg) && !IsChild(hwndimg,hwnd))
  668.         return 0;
  669.         GetClientRect(hwndimgchild, &rect);
  670.         ScreenToClient(hwndimgchild, &pt);
  671.         return PtInRect(&rect, pt);
  672. }
  673.  
  674. /* returns true if cursor in client area of GSview window */
  675. BOOL
  676. in_client_area()
  677. {
  678. RECT rect;
  679. POINT pt;
  680. HWND hwnd;
  681.         GetCursorPos(&pt);
  682.     hwnd = WindowFromPoint(pt);
  683.     if ((hwnd != hwndimg) && !IsChild(hwndimg,hwnd))
  684.         return 0;
  685.         GetClientRect(hwndimg, &rect);
  686.         ScreenToClient(hwndimg, &pt);
  687.         return PtInRect(&rect, pt);
  688. }
  689.  
  690. /* returns true if cursor in info area or button area of GSview windows */
  691. BOOL
  692. in_info_area()
  693. {
  694. RECT rect;
  695. POINT pt;
  696. HWND hwnd;
  697.         GetCursorPos(&pt);
  698.     hwnd = WindowFromPoint(pt);
  699.     if ((hwnd != hwndimg) && !IsChild(hwndimg,hwnd))
  700.         return 0;
  701.         ScreenToClient(hwndimg, &pt);
  702.  
  703.         GetClientRect(hwndimg, &rect);
  704.     rect.bottom = img_offset.y;
  705.     if (PtInRect(&rect, pt))
  706.         return TRUE;
  707.         GetClientRect(hwndimg, &rect);
  708.     rect.right = img_offset.x;
  709.         return PtInRect(&rect, pt);
  710. }
  711.  
  712. BOOL
  713. get_cursorpos(float *x, float *y)
  714. {
  715. RECT rect;
  716. POINT pt;
  717.     if (hwndimgchild && IsWindow(hwndimgchild)) {
  718.     GetClientRect(hwndimgchild, &rect);
  719.     GetCursorPos(&pt);
  720.     ScreenToClient(hwndimgchild, &pt);
  721.     if (PtInRect(&rect, pt)) {
  722.         *x = bitmap_scrollx+pt.x;
  723.         *y = display.height-1 - (bitmap_scrolly+pt.y);
  724.         transform_cursorpos(x, y);
  725.         return TRUE;
  726.     }
  727.     }
  728.     return FALSE;
  729. }
  730.  
  731. void
  732. cursorpos_paint(HDC hdc)
  733. {
  734. float x, y;
  735. char buf[32];
  736.     SetBkMode(hdc, TRANSPARENT);
  737.         FillRect(hdc, &info_coord, GetStockObject(LTGRAY_BRUSH));
  738.     /* show coordinate */
  739.     if (get_cursorpos(&x, &y)) {
  740.         switch(option.unit) {
  741.            case IDM_UNITPT:   
  742.           sprintf(buf,"%.0f, %.0fpt", x, y);
  743.           break;
  744.            case IDM_UNITMM:   
  745.           sprintf(buf,"%.0f, %.0fmm", x/72*25.4, y/72*25.4);
  746.           break;
  747.            case IDM_UNITINCH:   
  748.           sprintf(buf,"%.1f, %.1fin", x/72, y/72);
  749.           break;
  750.         }
  751.         SetTextAlign(hdc, TA_RIGHT);
  752.         TextOut(hdc, info_coord.right-1, info_coord.top, buf, strlen(buf));
  753.     }
  754. }
  755.  
  756. /* paint brief info area */
  757. void
  758. info_paint(HWND hwnd, HDC hdc)
  759. {
  760. RECT rect;
  761. int i;
  762. char buf[MAXSTR];
  763. char fmt[MAXSTR];
  764. HFONT old_hfont;
  765.     SetBkMode(hdc, TRANSPARENT);
  766.     if (info_font)
  767.         old_hfont = SelectObject(hdc, info_font);
  768.     if (info_rect.bottom) {
  769.         GetClientRect(hwnd, &rect);
  770.         rect.top = 0;
  771.         rect.left = info_rect.left;
  772.         rect.bottom = info_rect.bottom;
  773.         FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  774.         SelectPen(hdc, GetStockObject(BLACK_PEN));
  775.         MoveTo(hdc, rect.left, rect.bottom);
  776.         LineTo(hdc, rect.right, rect.bottom);
  777.         if (is_win95) {
  778.         SelectPen(hdc, GetStockObject(WHITE_PEN));
  779.         MoveTo(hdc, rect.left, rect.top+1);
  780.         LineTo(hdc, rect.right, rect.top+1);
  781.         SelectPen(hdc, GetStockObject(BLACK_PEN));
  782.         MoveTo(hdc, rect.left, rect.top);
  783.         LineTo(hdc, rect.right, rect.top);
  784.         }
  785.     }
  786.     /* write file information */
  787.     if (psfile.name[0] != '\0') {
  788.         i = LoadString(phInstance, IDS_FILE, buf, sizeof(buf));
  789.         GetFileTitle(psfile.name, buf+i, (WORD)(sizeof(buf)-i));
  790.         TextOut(hdc, info_file.x, info_file.y, buf, strlen(buf));
  791.         if (waiting) {
  792.         TextOut(hdc, info_page.x, info_page.y, szWait, strlen(szWait));
  793.         }
  794.         else {
  795.           if (doc!=(PSDOC *)NULL) {
  796.         int n = map_page(psfile.pagenum - 1);
  797.         i = LoadString(phInstance, IDS_PAGEINFO, fmt, sizeof(fmt));
  798.         if (doc->pages)
  799.             sprintf(buf, fmt, doc->pages[n].label ? doc->pages[n].label : " ",psfile.pagenum,  doc->numpages);
  800.         else
  801.             sprintf(buf, fmt, " " ,psfile.pagenum,  doc->numpages);
  802.         if (zoom)
  803.             strcat(buf, "  Zoomed");
  804.         TextOut(hdc, info_page.x, info_page.y, buf, strlen(buf));
  805.           }
  806.           else {
  807.         if (is_pipe_done())
  808.             i = LoadString(phInstance, IDS_NOMORE, buf, sizeof(buf));
  809.         else {
  810.             i = LoadString(phInstance, IDS_PAGE, buf, sizeof(buf));
  811.             sprintf(buf+i, "%d", psfile.pagenum);
  812.         }
  813.         TextOut(hdc, info_page.x, info_page.y, buf, strlen(buf));
  814.           }
  815.           /* show coordinate */
  816.           cursorpos_paint(hdc);
  817.         }
  818.     }
  819.     else {
  820.         i = LoadString(phInstance, IDS_NOFILE, buf, sizeof(buf));
  821.         TextOut(hdc, info_file.x, info_file.y, buf, strlen(buf));
  822.         if (waiting) {
  823.         TextOut(hdc, info_page.x, info_page.y, szWait, strlen(szWait));
  824.         }
  825.     }
  826.     if (info_font)
  827.         SelectObject(hdc, old_hfont);
  828. }
  829.  
  830.  
  831. HWND hbutton_info;
  832.  
  833. /* subclass button WndProc to give focus back to parent window */
  834. LRESULT CALLBACK _export
  835. MenuButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  836. {
  837.     switch(message) {
  838.         case WM_LBUTTONUP:
  839.         {
  840.         RECT rect;
  841.         POINT pt;
  842.         GetWindowRect(hwnd, &rect);
  843.         GetCursorPos(&pt);
  844.         if (PtInRect(&rect, pt))
  845.             SendMessage(GetParent(hwnd), WM_COMMAND, GetWindowID(hwnd), 0L);
  846.         SetFocus(GetParent(hwnd));
  847.         }
  848.         break;
  849. #ifdef NOTUSED
  850.     case WM_SETCURSOR:
  851.         /* track cursor and display button info */
  852.         if (hwnd != hbutton_info) {
  853.             char buf[MAXSTR];
  854.             hbutton_info = hwnd;
  855.             load_string(GetWindowID(hwnd), buf, sizeof(buf));
  856.             hdc = BeginPaint(hwnd, &ps);
  857.             SetBkMode(hdc, TRANSPARENT);
  858.             if (info_rect.bottom) {
  859.                 GetClientRect(hwnd, &rect);
  860.                 rect.top = 0;
  861.                 rect.left = info_rect.left;
  862.                 rect.bottom = info_rect.bottom;
  863.                 FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  864.                 SelectPen(hdc, GetStockObject(BLACK_PEN));
  865.                 MoveTo(hdc, rect.left, rect.bottom);
  866.                 LineTo(hdc, rect.right, rect.bottom);
  867.             }
  868.             TextOut(hdc, info_file.x, info_file.y, buf, strlen(buf));
  869.             EndPaint(hwnd, &ps);
  870.         }
  871.         InvalidateRect(hwndimg, &info_rect, FALSE);
  872.         UpdateWindow(hwndimg);
  873.         break;
  874. #endif
  875.     }
  876.     return CallWindowProc(lpfnButtonWndProc, hwnd, message, wParam, lParam);
  877. }
  878.  
  879.  
  880. BOOL
  881. set_timer(UINT period)
  882. {
  883.     timeout_count = period;
  884.     bTimeout = FALSE;
  885.     if (SetTimer(hwndimg, ID_MYTIMER, 1000, NULL) != 0) {
  886.         bTimerSet = TRUE;
  887.         return TRUE;
  888.     }
  889.  
  890.     bTimerSet = FALSE;
  891.     gserror(IDS_NOTIMER, NULL, MB_ICONINFORMATION, SOUND_TIMEOUT);
  892.     return FALSE;
  893. }
  894.  
  895. void
  896. clear_timer()
  897. {
  898.     if (bTimerSet)
  899.         KillTimer(hwndimg, ID_MYTIMER);
  900.     bTimerSet = FALSE;
  901.     bTimeout = FALSE;
  902.     EnableWindow(hwndimg, TRUE);
  903. }
  904.  
  905.  
  906. /* remove temporary files etc. */
  907. void
  908. gsview_close()
  909. {
  910.     gs_close();
  911.     pipeclose();
  912.     print_cleanup();
  913.     if (page_list.select)
  914.         free(page_list.select);
  915.     page_list.select = NULL;
  916.     if (doc)
  917.         psfree(doc);
  918.     doc = (PSDOC *)NULL;
  919.     if (option.settings)
  920.         write_profile();
  921.     SetCursor(GetClassCursor((HWND)NULL));
  922.     if (info_font)
  923.         DeleteObject(info_font);
  924.     return;
  925. }
  926.  
  927.  
  928. void
  929. copy_clipboard()
  930. {
  931.     if (hwndimgchild && IsWindow(hwndimgchild))
  932.         SendMessage(hwndimgchild, WM_GSVIEW, COPY_CLIPBOARD, NULL);
  933. }
  934.