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

  1. /* Copyright (C) 1993, 1994, 1995, 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. /* gvpm.c */
  19. /* Main routines for PM GSview */
  20. #define INCL_WINSTDDRAG
  21. #include "gvpm.h"
  22. #ifdef __EMX__
  23. #include "sys/ioctl.h"
  24. #endif
  25. #include "gvphelp.h"   /* generated by doc2ipf.c */
  26.  
  27.  
  28. char szAppName[MAXSTR] = "PM GSview";
  29. char szHelpTopic[MAXSTR];
  30. char szWait[MAXSTR];
  31. char szExePath[MAXSTR];
  32. char szHelpFile[MAXSTR];
  33. char szFindText[MAXSTR];
  34. char szIniFile[MAXSTR];
  35. char szMMini[MAXSTR];
  36. char previous_filename[MAXSTR];
  37. const char szScratch[] = "gv";    /* temporary filename prefix */
  38. HAB hab;        /* Anchor Block */
  39. HELPINIT hi_help;
  40. ULONG os_version;
  41. HWND hwnd_frame;
  42. HWND hwnd_bmp;
  43. HWND hwnd_status;
  44. HWND hwnd_button;
  45. HWND hwnd_help;
  46. HWND hwnd_modeless;    /* any modeless dialog box */
  47. HWND hptr_crosshair;
  48. HACCEL haccel;
  49. POINTL buttonbar;
  50. POINTL statusbar;
  51. POINTL info_file;
  52. POINTL info_page;
  53. POINTL scroll_pos;
  54. RECTL info_coord;
  55. BOOL waiting;
  56. TID queue_tid;
  57. TID term_tid;
  58. #define SB_TOP 20
  59. #define SB_BOTTOM 21
  60. GVIEW gsview;        /* GSview structure */
  61. PSFILE psfile;        /* Postscript file structure */
  62. BMAP bitmap;        /* Bitmap structure */
  63. PROG gsprog;        /* Ghostscript program structure */
  64. PROG pdfconv;        /* Ghostscript running PDF converter */
  65. OPTIONS option;        /* GSview options (saved in INI file) */
  66. DISPLAY display;    /* Display parameters */
  67. PRINTER printer;    /* Printer GS parameters */
  68. PSDOC *doc;
  69.  
  70. int page_extra;            /* extra pages to skip */
  71. int page_skip = 5;        /* number of pages to skip in IDM_NEXTSKIP or IDM_PREVSKIP */
  72. BOOL changed_version = FALSE;    /* to warn user to update Ghostscript Command */
  73. BOOL zoom = FALSE;        /* true if display zoomed */
  74. BOOL debug = FALSE;        /* /D command line option used */
  75. struct page_list_s page_list;
  76. struct sound_s sound[NUMSOUND] = {
  77.     {"SoundOutputPage", IDS_SNDPAGE, ""},
  78.     {"SoundNoPage", IDS_SNDNOPAGE, BEEP},
  79.     {"SoundNoNumbering", IDS_SNDNONUMBER, ""},
  80.     {"SoundNotOpen", IDS_SNDNOTOPEN, ""},
  81.     {"SoundError", IDS_SNDERROR, BEEP},
  82.     {"SoundTimeout", IDS_SNDTIMEOUT, ""},
  83.     {"SoundStart", IDS_SNDSTART, ""},
  84.     {"SoundExit", IDS_SNDEXIT, ""},
  85. };
  86. PFN_MciPlayFile pfnMciPlayFile;
  87.  
  88. /* button bar */
  89. struct button *buttonhead, *buttontail;
  90. BOOL button_down;
  91. struct button *button_current;
  92. struct button *button_info;
  93. POINTL button_shift;
  94. POINTL button_size;
  95.  
  96. MRESULT EXPENTRY ClientWndProc(HWND, ULONG, MPARAM, MPARAM);
  97. MRESULT EXPENTRY FrameWndProc(HWND, ULONG, MPARAM, MPARAM);
  98. MRESULT EXPENTRY StatusWndProc(HWND, ULONG, MPARAM, MPARAM);
  99. MRESULT EXPENTRY ButtonWndProc(HWND, ULONG, MPARAM, MPARAM);
  100. PFNWP OldFrameWndProc;
  101.  
  102. BOOL scan_bitmap(BMAP *pbm);
  103. HBITMAP make_bitmap(BMAP *, ULONG, ULONG, ULONG, ULONG, ULONG);
  104. void cursorpos_paint(HPS hps);
  105. void map_pt_to_pixel(float *x, float *y);
  106. MRESULT DragOver(PDRAGINFO);
  107. MRESULT Drop(PDRAGINFO);
  108.  
  109. void
  110. update_scroll_bars(void)
  111. {
  112.     /* Cause update of scroll bars etc. */
  113.     SWP swp;
  114.     WinQueryWindowPos(hwnd_bmp, &swp);
  115.     WinSendMsg(hwnd_bmp, WM_SIZE, MPFROM2SHORT(swp.cx, swp.cy), MPFROM2SHORT(swp.cx, swp.cy));
  116. }
  117.  
  118. /* temporary until status line created */
  119. void
  120. update_title(void)
  121. {
  122. char buf[256];
  123. char *state;
  124. char page[256];
  125. char *progname = "PM GSview";
  126.     if (display.page)
  127.         state = "PAGE";
  128.     else if (display.sync)
  129.         state = "SYNC";
  130.     else
  131.         state = "OTHER";
  132.  
  133.     if (psfile.name[0]) {
  134.         if (doc != (PSDOC *)NULL) {
  135.         int n = map_page(psfile.pagenum - 1);
  136.         if (doc->pages)
  137.             sprintf(page, "'%s' %d of %d", doc->pages[n].label ? doc->pages[n].label : " ",psfile.pagenum,  doc->numpages);
  138.         else
  139.             sprintf(page, "'' %d of %d", psfile.pagenum, doc->numpages);
  140.     
  141.             sprintf(buf, "%s - %s - %s - %s", progname,
  142.             psfile.name, page, state);
  143.         }
  144.         else {
  145.         sprintf(buf, "%s - %s - %d -%s", progname,
  146.             psfile.name, psfile.pagenum, state);
  147.         }
  148.     }
  149.     else {
  150.         sprintf(buf, "%s - No File", progname);
  151.     }
  152.     WinSetWindowText(hwnd_frame, buf);
  153. }
  154.  
  155. /* display thread */
  156. /* abort if display.abort TRUE */
  157. void 
  158. display_thread(void *arg)
  159. {
  160.     do_output();
  161. /* avoid bug in gs 2.9.4 */
  162. {int i;
  163. for (i=0; i<80; i++)
  164.     fputs("\r\n",gsprog.input);
  165.     fflush(gsprog.input);
  166.     dfclose();
  167.     display.busy = FALSE;
  168.     display.abort = FALSE;
  169.     display.do_endfile = FALSE;
  170.     display.do_resize = FALSE;
  171.     display.do_display = FALSE;
  172.     if (!gsprog.valid) {
  173. /*        WinPostMsg(hwnd_bmp, WM_GSCLOSE, MPFROMLONG(0), MPFROMLONG(0)); */
  174.         gs_close();
  175.     }
  176.     DosPostEventSem(display.done);
  177. }
  178.  
  179. #ifdef NOTUSED
  180. /* not used */
  181. /* copy psfile.file to GS */
  182. /* abort copy if display.abort TRUE */
  183. void 
  184. copy_thread(void *arg)
  185. {
  186. #define COPY_BUF_SIZE 4096
  187. char *buffer;
  188. int count;
  189.     if ((buffer = malloc(COPY_BUF_SIZE)) != (char *)NULL) {
  190.         while ( !display.abort &&
  191.         (count = fread(buffer, 1, COPY_BUF_SIZE, psfile.file)) != 0 )
  192.             fwrite(buffer, 1, count, gsprog.input);
  193.         free(buffer);
  194.     }
  195.     fclose(psfile.file);
  196. /*    fputs("quit\n", gsprog.input); */
  197.     fflush(gsprog.input);
  198.     display.busy = FALSE;
  199.     display.abort = FALSE;
  200.     DosPostEventSem(display.done);
  201. }
  202. #endif
  203.  
  204.  
  205. /* Queue thread */
  206. /* This thread waits for queue messages from gsos2.exe */
  207. /* This thread must NOT call C library functions */
  208. VOID APIENTRY queue_thread(ULONG unused)
  209. {
  210.     REQUESTDATA Request;
  211.     ULONG DataLength;
  212.     PVOID DataAddress;
  213.     BYTE ElemPriority;
  214.     unused = unused;    /* to shut up warning */
  215.     while ( !DosReadQueue(gsview.queue, &Request, &DataLength, &DataAddress, 
  216.             0, DCWW_WAIT, &ElemPriority, (HEV)NULL) ) {
  217.         switch(Request.ulData) {
  218.         case GS_UPDATING:
  219.                 WinPostMsg(hwnd_bmp, WM_GSUPDATING, MPFROMLONG(0), MPFROMLONG(0));
  220.             break;
  221.         case GS_SYNC:
  222.                 WinPostMsg(hwnd_bmp, WM_GSSYNC, MPFROMLONG(0), MPFROMLONG(0));
  223.             break;
  224.         case GS_PAGE:
  225.                 WinPostMsg(hwnd_bmp, WM_GSPAGE, MPFROMLONG(0), MPFROMLONG(0));
  226.             break;
  227.         case GS_CLOSE:
  228.                 WinPostMsg(hwnd_bmp, WM_GSCLOSE, MPFROMLONG(0), MPFROMLONG(0));
  229.             break;
  230.         case GS_ERROR:
  231.                 WinPostMsg(hwnd_bmp, WM_GSERROR, MPFROMLONG(0), MPFROMLONG(0));
  232.             break;
  233.         case GS_PALCHANGE:
  234.                 WinPostMsg(hwnd_bmp, WM_GSPALCHANGE, MPFROMLONG(0), MPFROMLONG(0));
  235.             break;
  236.         case GS_BEGIN:
  237.                 WinPostMsg(hwnd_bmp, WM_GSBEGIN, MPFROMLONG(0), MPFROMLONG(0));
  238.             break;
  239.         case GS_END:
  240.                 WinPostMsg(hwnd_bmp, WM_GSEND, MPFROMLONG(0), MPFROMLONG(0));
  241.             break;
  242.         }
  243.     }
  244. }
  245.  
  246. /* termination queue thread */
  247. /* This thread waits for termination messages */
  248. /* This thread must NOT call C library functions */
  249. VOID APIENTRY term_thread(ULONG unused)
  250. {
  251.     REQUESTDATA Request;
  252.     ULONG DataLength;
  253.     PVOID DataAddress;
  254.     BYTE ElemPriority;
  255.     WORD *pword;
  256.     unused = unused;    /* to shut up warning */
  257.     while ( !DosReadQueue(gsview.term_queue, &Request, &DataLength, &DataAddress, 
  258.             0, DCWW_WAIT, &ElemPriority, (HEV)NULL) ) {
  259.         pword = DataAddress;
  260.         /* should really build a list of programs and search the list */
  261.         if (*pword == gsprog.session_id) {
  262.             WinPostMsg(hwnd_bmp, WM_GSCLOSE, MPFROMLONG(0), MPFROMSHORT(pword[1]));
  263.         }
  264.         else if (*pword == printer.prog.session_id) {
  265.         WinPostMsg(hwnd_bmp, WM_GSPRNEXIT, MPFROMP(&printer), MPFROMSHORT(pword[1]));
  266.         }
  267.         DosFreeMem(DataAddress);
  268.     }
  269.     term_tid = 0;
  270. }
  271.  
  272. void
  273. exit_func(void)
  274. {
  275.     DosCloseEventSem(gsview.next_event);
  276.     DosCloseMutexSem(gsview.bmp_mutex);
  277.     DosCloseQueue(gsview.queue);
  278.     if (bitmap.pbmi)
  279.         DosFreeMem((PVOID)bitmap.pbmi);
  280.     if (gsprog.valid) {
  281.         stop_pgm(&gsprog);
  282.     }
  283.     if (printer.prog.valid) {
  284.         /* clean up after printer */
  285.         stop_pgm(&printer.prog);
  286.         if ((printer.cfname[0] != '\0') && !debug)
  287.             unlink(printer.cfname);
  288.         printer.cfname[0] = '\0';
  289.         if ((printer.fname[0] != '\0') && !debug)
  290.             unlink(printer.fname);
  291.         printer.fname[0] = '\0';
  292.     }
  293.     if (psfile.ispdf && psfile.name[0] && psfile.pdftemp[0])
  294.         unlink(psfile.pdftemp);  /* remove temporary DSC file */
  295.     if (option.settings)
  296.         write_profile();
  297.     DosCloseQueue(gsview.term_queue);
  298. }
  299.  
  300. int
  301. main(int argc, char *argv[])
  302. {
  303.   HMQ hand_mq;        /* message queue */
  304.   QMSG q_mess;        /* queue message */
  305.   ULONG flFlags;    /* Window frame definition */
  306.   APIRET rc = 0;
  307.   SWP swp;
  308.  
  309.   hab = WinInitialize(0);    /* Get the Anchor Block */
  310.  
  311.   hand_mq = WinCreateMsgQueue(hab, 0); /* start a queue */
  312.  
  313.   if (argc > 4) {
  314.     rc = 1;
  315.     error_message("Usage: gvpm [/D] [/F] [/P] [/S[port]] [filename]");
  316.   }
  317.  
  318.   rc = gsview_init(argc, argv);
  319.  
  320.   atexit(exit_func);
  321.  
  322.   if (!rc) {
  323.         WinShowWindow(hwnd_frame, TRUE);
  324.     haccel = WinQueryAccelTable(hab, hwnd_frame);
  325.     /* create help window */
  326.     hi_help.cb = sizeof(HELPINIT);
  327.     hi_help.ulReturnCode = 0;
  328.     hi_help.pszTutorialName = NULL;
  329.     hi_help.phtHelpTable = NULL;
  330.     hi_help.hmodAccelActionBarModule = 0;
  331.     hi_help.idAccelTable = 0;
  332.     hi_help.idActionBar = 0;
  333.     hi_help.pszHelpWindowTitle=(PSZ)"PM GSview Help";
  334.     hi_help.hmodHelpTableModule = 0;
  335.     hi_help.fShowPanelId = 0;
  336.     hi_help.pszHelpLibraryName = (PSZ)szHelpFile;
  337.     hwnd_help = WinCreateHelpInstance(hab, &hi_help);
  338.     if (!hwnd_help)
  339.         message_box("main: help not available", 0);
  340.     else
  341.         if (hi_help.ulReturnCode)
  342.         message_box("main: help terminated due to error", 0);
  343.     if (hwnd_help)
  344.         WinAssociateHelpInstance(hwnd_help, hwnd_frame);
  345.   }
  346.  
  347.   play_sound(SOUND_START);
  348.   /* message loop */
  349.   while (!rc && WinGetMsg(hab, &q_mess, 0L, 0, 0))
  350.       WinDispatchMsg(hab, &q_mess);
  351.  
  352.   play_sound(SOUND_EXIT);
  353.   /* Shut down the application window and queue */
  354.   DosKillThread(queue_tid);
  355.   DosKillThread(term_tid);
  356.   term_tid = 0;
  357.   if (hwnd_help)
  358.       WinDestroyHelpInstance(hwnd_help);
  359.   WinDestroyWindow(hwnd_frame);
  360.   WinDestroyMsgQueue(hand_mq);
  361.   WinTerminate(hab);
  362.   return rc;
  363. }
  364.  
  365. #define MAX_PAL_SIZE 256
  366. void
  367. make_palette(BMAP *pbm)
  368. {
  369. ULONG tbl[MAX_PAL_SIZE];
  370. PRGB2 palptr = (PRGB2) ((PBYTE)(pbm->pbmi) + pbm->pbmi->cbFix);
  371. RGB *old_palptr = (RGB *)palptr;
  372. int palcount = pbm->palimportant;
  373. int i;
  374. BOOL old_bmp = (pbm->pbmi->cbFix == sizeof(BITMAPINFOHEADER));
  375.     if (old_bmp) {
  376.     for (i=0; i<palcount; i++) {
  377.         tbl[i] = (old_palptr->bRed<<16) + (old_palptr->bGreen<<8) + (old_palptr->bBlue);
  378.         palptr++;
  379.     }
  380.     }
  381.     else {
  382.     for (i=0; i<palcount; i++) {
  383.         tbl[i] = (palptr->bRed<<16) + (palptr->bGreen<<8) + (palptr->bBlue);
  384.         palptr++;
  385.     }
  386.     }
  387.     if (display.hpal_exists)
  388.     GpiDeletePalette(display.hpal);
  389.     display.hpal = GpiCreatePalette(hab, 0L, LCOLF_CONSECRGB, palcount, tbl);
  390.     display.hpal_exists = TRUE;
  391. }
  392.  
  393.  
  394. /* scan bitmap */
  395. /* update bitmap structure */
  396. /* return value is TRUE if bitmap dimension has changed */
  397. BOOL
  398. scan_bitmap(BMAP *pbm)
  399. {
  400. PBITMAPINFO2 pbmi = pbm->pbmi;
  401. PBITMAPINFO old_pbmi = (PBITMAPINFO)pbmi;
  402. BOOL old_bmp = (pbmi->cbFix == sizeof(BITMAPINFOHEADER));
  403.  
  404.    if (old_bmp) {
  405.       /* it is a BITMAPINFO */
  406.       switch(old_pbmi->cBitCount) {
  407.         case 24:
  408.           pbm->palsize = 0;
  409.           break;
  410.         case 8:
  411.           pbm->palsize = 256;
  412.           break;
  413.         case 4:
  414.           pbm->palsize = 16;
  415.           break;
  416.         case 1:
  417.           pbm->palsize = 2;
  418.           break;
  419.         default:
  420.         pbm->valid = FALSE;
  421.           error_message("scan_bitmap: wrong number of bits"); /* panic */
  422.           return FALSE;
  423.     }
  424.     pbm->palimportant = pbm->palsize;
  425.     pbm->palsize = pbm->palsize * sizeof(RGB);
  426.         pbm->bits   = (PBYTE)old_pbmi + old_pbmi->cbFix + pbm->palsize;
  427.     pbm->width  = old_pbmi->cx;
  428.     pbm->height = old_pbmi->cy;
  429.     pbm->planes = old_pbmi->cPlanes;
  430.     pbm->depth  = old_pbmi->cBitCount;
  431.     }
  432.     else {
  433.      /* it is a BITMAPINFO2 */
  434.       switch(pbmi->cBitCount) {
  435.         case 24:
  436.           pbm->palsize = 0;
  437.           break;
  438.         case 8:
  439.           pbm->palsize = 256;
  440.           break;
  441.         case 4:
  442.           pbm->palsize = 16;
  443.           break;
  444.         case 1:
  445.           pbm->palsize = 2;
  446.           break;
  447.         default:
  448.         pbm->valid = FALSE;
  449.           error_message("scan_bitmap: wrong number of bits"); /* panic */
  450.           return FALSE;
  451.     }
  452.     if ( (pbmi->cbFix > (&(pbmi->cclrUsed) - &(pbmi->cbFix)))
  453.         && (pbmi->cclrUsed != 0) && (pbmi->cBitCount != 24) )
  454.         pbm->palsize = pbmi->cclrUsed;
  455.     pbm->palimportant = pbm->palsize;
  456.     if ( (pbmi->cbFix > (&(pbmi->cclrImportant) - &(pbmi->cbFix)))
  457.         && (pbmi->cclrImportant != 0) && (pbmi->cBitCount != 24) )
  458.         pbm->palimportant = pbmi->cclrImportant;
  459.     pbm->palsize = pbm->palsize * sizeof(RGB2);
  460.         pbm->bits   = (PBYTE)pbmi + pbmi->cbFix + pbm->palsize;
  461.     pbm->width  = pbmi->cx;
  462.     pbm->height = pbmi->cy;
  463.     pbm->planes = pbmi->cPlanes;
  464.     pbm->depth  = pbmi->cBitCount;
  465.     }
  466.  
  467.     if ((pbm->palsize != pbm->old_palsize) || (pbm->palimportant != pbm->old_palimportant)) {
  468.     if ( (pbm->depth == 8) && display.hasPalMan )
  469.         make_palette(pbm);
  470.     pbm->old_palimportant = pbm->palimportant;
  471.     }
  472.  
  473.     if ( (pbm->width   == pbm->old_width) && 
  474.          (pbm->height  == pbm->old_height) &&
  475.      (pbm->planes  == pbm->old_planes) && 
  476.      (pbm->depth   == pbm->old_depth) &&
  477.      (pbm->palsize == pbm->old_palsize) &&
  478.      (pbm->old_bmp == old_bmp) )
  479.     return FALSE;
  480.  
  481.     /* bitmap has changed */
  482.     pbm->old_width   = pbm->width;
  483.     pbm->old_height  = pbm->height;
  484.     pbm->old_planes  = pbm->planes;
  485.     pbm->old_depth   = pbm->depth;
  486.     pbm->old_palsize = pbm->palsize;
  487.     pbm->old_bmp     = old_bmp;
  488.     return TRUE;
  489. }
  490.  
  491. /* copy bitmap to the clipboard */
  492. void
  493. copy_clipboard(void)
  494. {
  495. HBITMAP hbmp;
  496.     if (!bitmap.valid) {
  497.     gserror(0, "Cannot copy to clipboard:\nNo Bitmap displayed", MB_ICONEXCLAMATION, SOUND_ERROR);
  498.     return;
  499.     }
  500.     if (WinOpenClipbrd(hab)) {
  501.     /* get bmp mutex to stop gs.exe changing bitmap while we copy it */
  502.     if (DosRequestMutexSem(gsview.bmp_mutex, 10000) == ERROR_TIMEOUT)
  503.         message_box("copy_clipboard: mutex timeout", 0);
  504.     if (scan_bitmap(&bitmap)) {
  505.         /* bitmap has changed */
  506.         update_scroll_bars();
  507.     }
  508.     hbmp = make_bitmap(&bitmap, 0, 0, bitmap.width, bitmap.height, bitmap.depth);
  509.     if (hbmp) {
  510.         WinEmptyClipbrd(hab);
  511.         WinSetClipbrdData(hab, (ULONG)hbmp, CF_BITMAP, CFI_HANDLE);
  512.     }
  513.     
  514.     DosReleaseMutexSem(gsview.bmp_mutex);
  515.     WinCloseClipbrd(hab);
  516.     }
  517. }
  518.  
  519. HBITMAP
  520. make_bitmap(BMAP *pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth)
  521. {
  522. HDC hdcMem = DEV_ERROR;
  523. HPS hps = GPI_ERROR;
  524. HBITMAP hbmp = GPI_ERROR, hbmr = HBM_ERROR;
  525. SIZEL sizePS;
  526. BITMAPINFOHEADER2 bmih;
  527.  
  528.     if ( (left == right) || (bottom == top) )
  529.         return (HBITMAP)NULL;
  530.  
  531.     if (right > pbm->width)
  532.         right = pbm->width;
  533.     if (left > pbm->width)
  534.         left = 0;
  535.     if (top > pbm->height)
  536.         top = pbm->height;
  537.     if (bottom > pbm->height)
  538.         bottom = 0;
  539.         
  540.     memset(&bmih, 0, sizeof(bmih));
  541.     bmih.cbFix = sizeof(BITMAPINFOHEADER2);
  542.     bmih.cx = right - left;
  543.     bmih.cy = top - bottom;
  544.     bmih.cPlanes = 1;
  545.     bmih.cBitCount = depth;
  546.  
  547.     /* create memory DC compatible with screen */
  548.     hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 0L, NULL, NULLHANDLE);
  549.  
  550.     sizePS.cx = right - left;
  551.     sizePS.cy = top - bottom;
  552.     if (hdcMem != DEV_ERROR)
  553.         hps = GpiCreatePS(hab, hdcMem, &sizePS, 
  554.         PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  555.  
  556.     if (hps != GPI_ERROR)
  557.         hbmp = GpiCreateBitmap(hps, &bmih, 0L, NULL, NULL);
  558.  
  559.     if (hbmp != GPI_ERROR)
  560.         hbmr = GpiSetBitmap(hps, hbmp);
  561.  
  562.  
  563.     if (hbmr != HBM_ERROR) {
  564.         LONG rc;
  565.         ERRORID eid;
  566.               POINTL apts[4];
  567.         /* target is inclusive */
  568.         apts[0].x = 0;
  569.         apts[0].y = 0;
  570.         apts[1].x = right - left - 1;
  571.         apts[1].y = top - bottom - 1;
  572.         /* source is not inclusive of top & right borders */
  573.         apts[2].x = left;
  574.         apts[2].y = bottom;
  575.         apts[3].x = right;
  576.         apts[3].y = top;
  577.  
  578.         rc = 0;
  579.         eid = WinGetLastError(hab);
  580.             rc = GpiDrawBits(hps, pbm->bits, pbm->pbmi, 4, apts, 
  581.             (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
  582.         if (rc==0) {
  583.             char buf[256];
  584.             eid = WinGetLastError(hab);
  585.             sprintf(buf,"make_bitmap: GpiDrawBits rc = %08x, eid = %08x",rc, eid);
  586.             message_box(buf, 0);
  587.         }
  588.     }
  589.     
  590.     if (hbmr != HBM_ERROR)
  591.         GpiSetBitmap(hps, (ULONG)0);
  592.     if (hps != GPI_ERROR)
  593.         GpiDestroyPS(hps);
  594.     if (hdcMem != DEV_ERROR)
  595.         DevCloseDC(hdcMem);
  596.  
  597.     if ( (hbmr == HBM_ERROR) || (hdcMem == DEV_ERROR) ||
  598.         (hbmp == GPI_ERROR) || (hps == GPI_ERROR) ) {
  599.         if (hbmp != GPI_ERROR)
  600.             GpiDeleteBitmap(hbmp);
  601.         return 0;
  602.     }
  603.     return hbmp;
  604. }
  605.  
  606. MRESULT
  607. paint_bitmap(HPS ps, PRECTL prect, int scrollx, int scrolly)
  608. {
  609.     POINTL apts[4];
  610.     RECTL rect;
  611.     int wx, wy;
  612.     int ewx = 0;    /* empty area at right */
  613.     int ewy = 0;    /* empty area at top */
  614.     if (WinIsRectEmpty(hab, prect))
  615.     return 0;
  616.     /* source is not inclusive of top & right borders */
  617.     wx = prect->xRight - prect->xLeft;   /* update width */
  618.     wy = prect->yTop -   prect->yBottom; /* update height */
  619.     if (prect->xLeft < display.offset.x)
  620.     apts[2].x = 0;
  621.     else
  622.     apts[2].x = (prect->xLeft-display.offset.x)   + scrollx;
  623.     if (prect->yBottom < display.offset.y)
  624.         apts[2].y = 0;
  625.     else
  626.     apts[2].y = (prect->yBottom-display.offset.y) + scrolly;
  627.     if (apts[2].x > bitmap.width)
  628.         apts[2].x = bitmap.width;
  629.     if (apts[2].x + wx > bitmap.width) {
  630.         wx = bitmap.width - apts[2].x;
  631.     }
  632.     apts[3].x = apts[2].x + wx;
  633.     if (apts[2].y > bitmap.height)
  634.         apts[2].y = bitmap.height;
  635.     if (apts[2].y + wy > bitmap.height) {
  636.         wy = bitmap.height - apts[2].y;
  637.     }
  638.     apts[3].y = apts[2].y + wy;
  639.     /* target is inclusive */
  640. #ifdef NOTUSED
  641.     apts[0].x = prect->xLeft;
  642.     apts[0].y = prect->yBottom;
  643.     apts[1].x = prect->xLeft + wx - 1;
  644.     apts[1].y = prect->yBottom + wy - 1;
  645. #else
  646.     if (prect->xLeft < display.offset.x)
  647.     apts[0].x = display.offset.x;
  648.     else 
  649.     apts[0].x = prect->xLeft;
  650.     if (prect->yBottom < display.offset.y)
  651.      apts[0].y = display.offset.y;
  652.     else
  653.     apts[0].y = prect->yBottom;
  654.     apts[1].x = apts[0].x + wx - 1;
  655.     apts[1].y = apts[0].y + wy - 1;
  656. #endif
  657.  
  658. #ifdef NOTUSED
  659.     if ( (display.bitcount == 4)  /* standard VGA is buggy */
  660.     || ( (os_version==201100) && (display.bitcount==8) && (bitmap.depth==1)) /* S3 and ATI GU are buggy */
  661.          ) {
  662.     /* slow code to dodge OS/2 bugs */
  663.     /* this code double buffers the bitmap and works on a standard VGA
  664.      * but didn't work on an ATI Ultra Graphics Pro in 8514 emulation
  665.      */
  666.     /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 8bit/pixel bitmap */
  667.     HBITMAP hbmp;
  668.     /* create a bitmap */
  669.     hbmp = make_bitmap(&bitmap, apts[2].x, apts[2].y, apts[3].x, apts[3].y, bitmap.depth);
  670.     /* Draw it to the display */
  671.     if (hbmp) {
  672.         WinDrawBitmap(ps, hbmp, NULL, &apts[0], CLR_BLACK, CLR_WHITE, DBM_NORMAL);
  673.         GpiDeleteBitmap(hbmp);
  674.     }
  675.     }
  676.     else {
  677. #endif
  678.     /* fast code which doesn't always work */
  679.     /* This code works on the Trident SVGA and 8514 in 256 color mode,
  680.       * but GpiDrawBits fails with a SYS3175 on the standard VGA.
  681.      */
  682.     /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 1bit/pixel bitmap */
  683.     GpiDrawBits(ps, bitmap.bits, bitmap.pbmi, 4, apts, 
  684.         (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
  685. #ifdef NOTUSED
  686.     }
  687. #endif
  688.     /* Fill areas around page */
  689.     if (prect->yBottom < display.offset.y) {    /* bottom centre */
  690.     rect.yBottom = prect->yBottom;
  691.     rect.yTop = display.offset.y;
  692.     rect.xLeft = apts[0].x;
  693.     rect.xRight = rect.xLeft + wx;
  694.     WinFillRect(ps, &rect, SYSCLR_BUTTONMIDDLE);
  695.     }
  696.     if (prect->yTop > bitmap.height + display.offset.y) { /* bottom centre */
  697.     rect.yBottom = bitmap.height + display.offset.y;
  698.     rect.yTop = prect->yTop;
  699.     rect.xLeft = apts[0].x;
  700.     rect.xRight = rect.xLeft + wx;
  701.     WinFillRect(ps, &rect, SYSCLR_BUTTONMIDDLE);
  702.     }
  703.     if (prect->xLeft < display.offset.x) { /* left */
  704.     rect.yBottom = prect->yBottom;
  705.     rect.yTop = prect->yTop;
  706.     rect.xLeft = prect->xLeft;
  707.     rect.xRight = display.offset.x;
  708.     WinFillRect(ps, &rect, SYSCLR_BUTTONMIDDLE);
  709.     }
  710.     if (prect->xRight > bitmap.width + display.offset.x) { /* right */
  711.     rect.yBottom = prect->yBottom;
  712.     rect.yTop = prect->yTop;
  713.     rect.xLeft = bitmap.width + display.offset.x;
  714.     rect.xRight = prect->xRight;
  715.     WinFillRect(ps, &rect, SYSCLR_BUTTONMIDDLE);
  716.     }
  717.  
  718.     /* draw bounding box */
  719.     if ((doc != (PSDOC *)NULL) && option.show_bbox) {
  720.         POINTL pt;
  721.     float x, y;
  722.     /* map bounding box to device coordinates */
  723.     x = doc->boundingbox[LLX];
  724.     y = doc->boundingbox[LLY];
  725.     map_pt_to_pixel(&x, &y);
  726.     rect.xLeft   = (int)x;
  727.     rect.yBottom = (int)y;
  728.     x = doc->boundingbox[URX];
  729.     y = doc->boundingbox[URY];
  730.     map_pt_to_pixel(&x, &y);
  731.     rect.xRight  = (int)x;
  732.     rect.yTop    = (int)y;
  733.  
  734.     /* draw it inverted */
  735.     GpiSetColor(ps, CLR_TRUE);
  736.     GpiSetLineType(ps, LINETYPE_SHORTDASH);
  737.     GpiSetMix(ps, FM_XOR);
  738.     pt.x = rect.xLeft; pt.y = rect.yBottom;
  739.     GpiMove(ps, &pt);
  740.     pt.x = rect.xRight; /* might be better to use GpiPolyLine */
  741.     GpiLine(ps, &pt);
  742.     pt.y = rect.yTop;
  743.     GpiLine(ps, &pt);
  744.     pt.x = rect.xLeft;
  745.     GpiLine(ps, &pt);
  746.     pt.y = rect.yBottom;
  747.     GpiLine(ps, &pt);
  748.     GpiSetLineType(ps, LINETYPE_DEFAULT);
  749.     GpiSetMix(ps, FM_DEFAULT);
  750.     GpiSetColor(ps, CLR_TRUE);
  751.     }
  752.  
  753.     return 0;
  754. }
  755.  
  756. /* enable or disable a menu item */
  757. void
  758. enable_menu_item(int menuid, int itemid, BOOL enabled)
  759. {
  760. HWND hwndMenu;
  761. MENUITEM mi;
  762.     hwndMenu = WinWindowFromID(hwnd_frame, FID_MENU);
  763.     WinSendMsg(hwndMenu, MM_QUERYITEM, 
  764.         MPFROM2SHORT(menuid, TRUE), MPFROMP(&mi));
  765.     WinSendMsg(mi.hwndSubMenu, MM_SETITEMATTR, MPFROMLONG(itemid),
  766.         MPFROM2SHORT(MIA_DISABLED, enabled ? 0 : MIA_DISABLED));
  767. }
  768.  
  769.  
  770. /* This is the window function */
  771. MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG mess, 
  772.             MPARAM mp1, MPARAM mp2)
  773. {
  774.   char buf[256];
  775.  
  776.   static int cxClient, cyClient;
  777.   static int cxAdjust, cyAdjust;
  778.   static int nHscrollMax, nHscrollPos;
  779.   static int nVscrollMax, nVscrollPos;
  780.   int nHscrollInc;
  781.   int nVscrollInc;
  782.   HWND hwndScroll;
  783.   HPS hps;
  784.   RECTL rect;
  785.   ULONG ulclr;
  786.  
  787.     switch(mess) {
  788.     case WM_CREATE:
  789.         break;
  790.     case WM_ERASEBACKGROUND:
  791.         /* by returning TRUE, the Presentation Manager automatically clears
  792.          * the window each time the window is resized or moved.
  793.          */
  794.         if (!bitmap.valid)
  795.             return (MRESULT)TRUE;
  796.         break;
  797.     case WM_GSUPDATING:
  798.         /* this used to do the same as WM_GSBEGIN */
  799.         /* if we don't know the bitmap pointer, get it now */
  800.         if (!bitmap.valid) {
  801.             APIRET rc;
  802.             char name[256];
  803.             memset(&bitmap, 0, sizeof(bitmap));
  804.             sprintf(name, SHARED_NAME, gsview.id);
  805.               rc = DosGetNamedSharedMem((PVOID *)&bitmap.pbmi, name, PAG_READ);
  806.               if (rc) {
  807.             sprintf(buf, "Failed to open: bmp shared memory \"%s\" rc = %d", name, rc);
  808.             error_message(buf);
  809.             }
  810.             else
  811.                 bitmap.valid = TRUE;
  812.         }
  813.         return 0;
  814.     case WM_GSBEGIN:
  815.         display.page = FALSE;
  816.         display.sync = FALSE;
  817.         display.end = FALSE;
  818.         load_string(IDS_WAITDRAW, szWait, sizeof(szWait));
  819.         info_wait(TRUE);
  820.         if (!gsprog.valid) {
  821.             /* someone has killed GS */
  822.                 WinSendMsg(hwnd_bmp, WM_GSCLOSE, MPFROMLONG(0), MPFROMLONG(0));
  823.             return 0;
  824.         }
  825.         /* if we don't know the bitmap pointer, get it now */
  826.         if (!bitmap.valid) {
  827.             APIRET rc;
  828.             char name[256];
  829.             memset(&bitmap, 0, sizeof(bitmap));
  830.             sprintf(name, SHARED_NAME, gsview.id);
  831.               rc = DosGetNamedSharedMem((PVOID *)&bitmap.pbmi, name, PAG_READ);
  832.               if (rc) {
  833.             sprintf(buf, "Failed to open: bmp shared memory \"%s\" rc = %d", name, rc);
  834.             error_message(buf);
  835.             }
  836.             else
  837.                 bitmap.valid = TRUE;
  838.         }
  839.         /* should set update timer here */
  840.         return 0;
  841.     case WM_GSSYNC:
  842.         display.page = FALSE;
  843.         display.sync = TRUE;
  844. /* don't clear display.end since this stops us noticing end of non DSC document
  845.         display.end = FALSE;
  846. */
  847.         if (!WinInvalidateRect(hwnd_bmp, (PRECTL)NULL, TRUE))
  848.             error_message("error invalidating rect");
  849.           if (!WinUpdateWindow(hwnd_bmp))
  850.             error_message("error updating window");
  851. /*
  852.         if (!display.busy)
  853.             info_wait(FALSE);
  854. */
  855.         return 0;
  856.     case WM_GSPAGE:
  857.         play_sound(SOUND_PAGE);
  858.         display.page = TRUE;
  859.         display.sync = FALSE;
  860.         display.end = FALSE;
  861.         if (!WinInvalidateRect(hwnd_bmp, (PRECTL)NULL, TRUE))
  862.             error_message("error invalidating rect");
  863.           if (!WinUpdateWindow(hwnd_bmp))
  864.             error_message("error updating window");
  865.         info_wait(FALSE);
  866.         return 0;
  867.     case WM_GSCLOSE:
  868.         display.page = FALSE;
  869.         display.sync = FALSE;
  870.         bitmap.valid = FALSE;
  871.         /* mark bitmap as unused */
  872.         if (DosRequestMutexSem(gsview.bmp_mutex, 10000) == ERROR_TIMEOUT)
  873.                 message_box("ClientWndProc: WM_CLOSE: mutex timeout", 0);
  874.         DosEnterCritSec();
  875.         if (bitmap.pbmi)
  876.             DosFreeMem((PVOID)bitmap.pbmi);
  877.         memset(&bitmap, 0, sizeof(bitmap));
  878.         DosExitCritSec();
  879.         DosReleaseMutexSem(gsview.bmp_mutex);
  880.         update_scroll_bars();
  881.         if (display.busy)  {
  882.             int i, n;
  883.             char buf[2048];
  884.             gsprog.valid = FALSE; /* don't kill gsprog.input while display thread using it */
  885.             display.abort = TRUE;
  886. #ifdef __EMX__
  887.             /* flush pipe - not working */
  888.             n = -1;
  889.             while ( display.busy  && n ) {
  890.             i = ioctl(0, FIONREAD, &n);
  891.             if (n)
  892.                 read(0, buf, n > sizeof(buf) ? sizeof(buf) : n);
  893.             if (gsprog.input)
  894.                 fflush(gsprog.input);
  895.             DosSleep(0);    /* switch to next thread */
  896.             }
  897. #endif
  898.         }
  899.         else
  900.             cleanup_pgm(&gsprog);
  901.         info_wait(FALSE);
  902.         return 0;
  903.     case WM_GSERROR:
  904.         display.page = FALSE;
  905.         display.sync = FALSE;
  906.         display.end = FALSE;
  907.         if (display.busy)
  908.             display.abort = TRUE;
  909.         info_wait(FALSE);
  910.         message_box("Ghostscript Error\rSee Ghostscript window for more details", 0);
  911.             DosPostEventSem(gsview.next_event);
  912.         if (!display.busy)
  913.             cleanup_pgm(&gsprog);
  914.         return 0;
  915.     case WM_GSPALCHANGE:
  916.         /* do nothing yet */
  917.         return 0;
  918.     case WM_GSEND:
  919.         display.page = FALSE;
  920.         display.sync = FALSE;
  921.         display.end = TRUE;
  922.         if (!WinInvalidateRect(hwnd_bmp, (PRECTL)NULL, TRUE))
  923.             error_message("error invalidating rect");
  924.           if (!WinUpdateWindow(hwnd_bmp))
  925.             error_message("error updating window");
  926.         if (!display.busy)
  927.             info_wait(FALSE);
  928.         return 0;
  929.     case WM_GSPRNEXIT:
  930.         {   PRINTER *prn = (PRINTER *)mp1;
  931.             cleanup_pgm(&prn->prog);
  932.             if ((prn->cfname[0] != '\0') && !debug)
  933.                     unlink(prn->cfname);
  934.             prn->cfname[0] = '\0';
  935.             if ((prn->fname[0] != '\0') && !debug)
  936.                 unlink(prn->fname);
  937.             prn->fname[0] = '\0';
  938.         }
  939.         return 0;
  940.     case WM_INITMENU:
  941.         enable_menu_item(IDM_EDITMENU, IDM_COPYCLIP, bitmap.valid);
  942.         enable_menu_item(IDM_EDITMENU, IDM_PASTETO, bitmap.valid);
  943.         enable_menu_item(IDM_EDITMENU, IDM_ADDEPSMENU, bitmap.valid 
  944.                 && (doc != (PSDOC *)NULL) && doc->epsf);
  945.         enable_menu_item(IDM_EDITMENU, IDM_EXTEPSMENU, 
  946.             (psfile.preview == IDS_EPST) || (psfile.preview == IDS_EPSW));
  947.         WinSetAccelTable(hab, NULLHANDLE, hwnd_frame);    /* disable keyboard accelerators */
  948.         break;
  949.     case WM_MENUEND:
  950.         WinSetAccelTable(hab, haccel, hwnd_frame);    /* reenable keyboard accelerators */
  951.         break;
  952.     case WM_COMMAND:
  953.         if (LONGFROMMP(mp1) == IDM_DROP) {
  954.             char *cmd = (char *)mp2;
  955.             if ((cmd[0] == '-') || (cmd[0] == '/')) {
  956.             switch (toupper(cmd[1])) {
  957.                 case 'P':
  958.                       gsview_selectfile(cmd+2);
  959.                       gsview_print(FALSE);
  960.                   break;
  961.                 case 'F':
  962.                       gsview_selectfile(cmd+2);
  963.                       gsview_print(TRUE);
  964.                   break;
  965.                 case 'S':
  966.                   if (cmd[2] != ' ') {
  967.                 char *fname;
  968.                 /* skip over port name */
  969.                 for (fname=cmd+2; *fname && *fname!=' '; fname++)
  970.                   /* nothing */ ;
  971.                     /* skip blanks until file name */
  972.                     if (*fname) {
  973.                       *fname++ = '\0'; /* place null after port name */
  974.                       for (; *fname==' '; fname++)
  975.                         /* nothing */ ;
  976.                     }
  977.                     if (*fname) {
  978.                         /* found both filename and port */
  979.                         gsview_spool(fname, cmd+2);
  980.                         break;
  981.                     }
  982.                   }
  983.                       gsview_spool(cmd+2, (char *)NULL);
  984.                   break;
  985.                 default:
  986.                   gserror(IDS_BADCLI, cmd, MB_ICONEXCLAMATION, SOUND_ERROR);
  987.             }
  988.             }
  989.             else {
  990.             FILE *f;
  991.             /* only display file if it exists */
  992.             /* because starting GSview from Desktop menu sets cmd to d:\Desktop */
  993.             if ( (f=fopen(cmd,"rb")) != (FILE *)NULL ) {
  994.                 fclose(f);
  995.                     gsview_displayfile(cmd);
  996.             }
  997.             }
  998.             free(cmd);
  999.         }
  1000.         else {
  1001.             if (waiting) {
  1002.             switch(LONGFROMMP(mp1)) {
  1003.                     case IDM_INFO:
  1004.                     case IDM_SAVEDIR:
  1005.                     case IDM_SETTINGS:
  1006.                     case IDM_SAVESETTINGS:
  1007.                     case IDM_SOUNDS:
  1008.                     case IDM_HELPCONTENT:
  1009.                     case IDM_HELPSEARCH:
  1010.                     case IDM_ABOUT:
  1011.                 case IDM_EXIT:
  1012.                     /* these are safe to use when busy */
  1013.                 break;
  1014.                 default:
  1015.                     play_sound(SOUND_ERROR);
  1016.                     return 0;    /* Command not permitted now */
  1017.             }
  1018.             }
  1019.             if (LONGFROMMP(mp1) == IDM_PSTOEPS) {
  1020.             if (psfile.name[0] == '\0')    /* need open file */
  1021.                 WinSendMsg(hwnd, WM_COMMAND, MPFROMSHORT(IDM_OPEN), MPFROM2SHORT(CMDSRC_OTHER,FALSE));
  1022.             }
  1023.             gsview_command(LONGFROMMP(mp1));
  1024.         }
  1025.  
  1026.         if (display.do_endfile || display.do_resize || display.do_display) {
  1027.             if (display.busy && (display.do_display || display.do_resize)) {
  1028.             play_sound(SOUND_ERROR);
  1029.             break;
  1030.             }
  1031.             load_string(IDS_WAIT, szWait, sizeof(szWait));
  1032.             info_wait(TRUE);
  1033.             if (!gs_open()) {
  1034.                 info_wait(FALSE);
  1035.                 return FALSE;
  1036.             }
  1037.             if (display.busy) {
  1038.             play_sound(SOUND_ERROR);
  1039.             if (!gsprog.valid) {
  1040.                 message_box("Problem with gs.  Exit and restart PM GSview", 0);
  1041.                     info_wait(FALSE);
  1042.             }
  1043.             }
  1044.             else {
  1045.                 ULONG count;
  1046.                 dfreopen();
  1047.                 display.busy = TRUE;
  1048.                 DosResetEventSem(display.done, &count);
  1049. #ifdef NOTHREAD
  1050.             /* for debugging run it in thread 1 */
  1051.             display_thread(NULL);
  1052. #else
  1053. #ifdef __BORLANDC__
  1054.                 display.id = _beginthread(display_thread, 16384, NULL);
  1055. #else
  1056.                 display.id = _beginthread(display_thread, NULL, 16384, NULL);
  1057. #endif
  1058.                 if (display.id == -1) {
  1059.                   info_wait(FALSE);
  1060.               message_box("_beginthread() output thread failed", 0);
  1061.               display.busy = FALSE;
  1062.               display.abort = FALSE;
  1063.               display.do_endfile = FALSE;
  1064.               display.do_resize = FALSE;
  1065.               display.do_display = FALSE;
  1066.               play_sound(SOUND_ERROR);
  1067.                 }
  1068. #endif
  1069.             }
  1070.         }
  1071.         else
  1072.             info_wait(FALSE);
  1073.         break;
  1074.     case WM_REALIZEPALETTE:
  1075.         if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  1076.         hps = WinGetPS(hwnd);
  1077.         GpiSelectPalette(hps, display.hpal);
  1078.             if (WinRealizePalette(hwnd, hps, &ulclr) > 0)
  1079.             WinInvalidateRect(hwnd, NULL, FALSE);
  1080.         GpiSelectPalette(hps, (HPAL)NULL);
  1081.         WinReleasePS(hps);
  1082.             return 0;
  1083.         }
  1084.         break;    /* use default processing */
  1085.     case WM_PAINT:
  1086.         if (!bitmap.valid) {
  1087.             hps = WinBeginPaint(hwnd, (ULONG)0, &rect);
  1088.         WinFillRect(hps, &rect, CLR_BACKGROUND);
  1089.         WinEndPaint(hwnd);
  1090.         return 0;
  1091.         }
  1092.  
  1093.         /* Refresh the window each time the WM_PAINT message is received */
  1094.  
  1095.         /* get bmp mutex to stop gs.exe changing bitmap while we paint */
  1096.         if (DosRequestMutexSem(gsview.bmp_mutex, 10000) == ERROR_TIMEOUT)
  1097.             message_box("ClientWndProc: WM_PAINT: mutex timeout", 0);
  1098.         if (scan_bitmap(&bitmap))
  1099.         update_scroll_bars(); /* bitmap has changed */
  1100.  
  1101.         if (!bitmap.valid) {
  1102.             DosReleaseMutexSem(gsview.bmp_mutex);
  1103.             hps = WinBeginPaint(hwnd, (ULONG)0, &rect);
  1104.         WinFillRect(hps, &rect, CLR_BACKGROUND);
  1105.         WinEndPaint(hwnd);
  1106.         return 0;
  1107.         }
  1108.  
  1109.         hps = WinBeginPaint(hwnd, (HPS)NULL, &rect);
  1110.         if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  1111.             GpiSelectPalette(hps, display.hpal);
  1112.                 WinRealizePalette(hwnd, hps, &ulclr);
  1113.             paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1114.             GpiSelectPalette(hps, (HPAL)NULL);
  1115.         }
  1116.         else
  1117.             paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1118.         WinEndPaint(hwnd);
  1119.  
  1120.         DosReleaseMutexSem(gsview.bmp_mutex);
  1121.         return 0;
  1122.     case WM_MOVE:
  1123.         /* don't interrogate the window location immediately since */
  1124.         /* it causes the Diamond Stealth VL24 with IBM S3 drivers */
  1125.         /* to corrupt the display */
  1126.         DosSleep(50);
  1127.         if (hwnd_frame) {
  1128.         SWP swp;
  1129.         WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
  1130.         if (!(swp.fl & SWP_MINIMIZE)) {
  1131.             if (!(swp.fl & SWP_MAXIMIZE)) {
  1132.                 option.img_origin.x = swp.x;
  1133.                 option.img_origin.y = swp.y;
  1134.             }
  1135.             option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
  1136.         }
  1137.         }
  1138.         break;
  1139.     case WM_SIZE:
  1140.         cyClient = SHORT2FROMMP(mp2);
  1141.         cxClient = SHORT1FROMMP(mp2);
  1142.  
  1143.         cyAdjust = min(bitmap.height, cyClient) - cyClient;
  1144.         cyClient += cyAdjust;
  1145.  
  1146.         nVscrollMax = max(0, bitmap.height - cyClient);
  1147.         nVscrollPos = min(nVscrollPos, nVscrollMax);
  1148.         scroll_pos.y = nVscrollMax - nVscrollPos;
  1149.  
  1150.         if (!bitmap.valid)
  1151.             cyClient = cyAdjust = nVscrollMax = nVscrollPos;
  1152.  
  1153.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
  1154.         WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nVscrollPos), 
  1155.             MPFROM2SHORT(0, nVscrollMax));
  1156.         if (bitmap.valid)
  1157.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cyClient, bitmap.height),
  1158.             MPFROMLONG(0));
  1159.         else
  1160.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
  1161.             MPFROMLONG(0));
  1162.  
  1163.         cxAdjust = min(bitmap.width,  cxClient) - cxClient;
  1164.         cxClient += cxAdjust;
  1165.  
  1166.         nHscrollMax = max(0, bitmap.width - cxClient);
  1167.         nHscrollPos = min(nHscrollPos, nHscrollMax);
  1168.         scroll_pos.x = nHscrollPos;
  1169.  
  1170.         if (!bitmap.valid)
  1171.             cxClient = cxAdjust = nHscrollMax = nHscrollPos;
  1172.  
  1173.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
  1174.         WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nHscrollPos), 
  1175.             MPFROM2SHORT(0, nHscrollMax));
  1176.         if (bitmap.valid)
  1177.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cxClient, bitmap.width),
  1178.             MPFROMLONG(0));
  1179.         else
  1180.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
  1181.             MPFROMLONG(0));
  1182.  
  1183.         if ( option.fit_page && (cxAdjust!=0 || cyAdjust!=0) ) {
  1184.                 SWP swp;
  1185.             /* don't interrogate the window location immediately since */
  1186.             /* it causes the Diamond Stealth VL24 with IBM S3 drivers */
  1187.             /* to corrupt the display */
  1188.             DosSleep(50);
  1189.                 WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
  1190.                 WinSetWindowPos(WinQueryWindow(hwnd, QW_PARENT), 0, 
  1191.                 swp.x, swp.y - cyAdjust,
  1192.                 swp.cx + cxAdjust, swp.cy + cyAdjust, SWP_SIZE | SWP_MOVE);
  1193.                 cxAdjust = cyAdjust = 0;
  1194.         }
  1195.         display.offset.x = -cxAdjust/2;
  1196.         display.offset.y = -cyAdjust/2;
  1197.             if (hwnd_frame) {
  1198.             SWP swp;
  1199.             WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
  1200.             if (!(swp.fl & SWP_MINIMIZE)) {
  1201.             if (!(swp.fl & SWP_MAXIMIZE)) {
  1202.                     option.img_size.x = swp.cx;
  1203.                     option.img_size.y = swp.cy;
  1204.             }
  1205.                 option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
  1206.             }
  1207.         }
  1208.         break;
  1209.     case WM_VSCROLL:
  1210.         switch(SHORT2FROMMP(mp2)) {
  1211.         case SB_LINEUP:
  1212.             nVscrollInc = -cyClient/16;
  1213.             break;
  1214.         case SB_LINEDOWN:
  1215.             nVscrollInc = cyClient/16;
  1216.             break;
  1217.         case SB_PAGEUP:
  1218.             nVscrollInc = min(-1,-cyClient);
  1219.             break;
  1220.         case SB_PAGEDOWN:
  1221.             nVscrollInc = max(1,cyClient);
  1222.             break;
  1223. #ifdef NOTUSED
  1224.         case SB_SLIDERTRACK:
  1225.             /* only do this for fast redraw modes */
  1226.             /* these are 8bit/pixel and 1bit/pixel */
  1227.                 if ( (bitmap.depth == 1) ||
  1228.                ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) ) {
  1229.             nVscrollInc = SHORT1FROMMP(mp2) - nVscrollPos;
  1230.             }
  1231.             else
  1232.             nVscrollInc = 0;
  1233. #endif
  1234.         case SB_SLIDERPOSITION:
  1235.             nVscrollInc = SHORT1FROMMP(mp2) - nVscrollPos;
  1236.             break;
  1237.         case SB_TOP:
  1238.             nVscrollInc = -nVscrollPos;
  1239.             break;
  1240.         case SB_BOTTOM:
  1241.             nVscrollInc = nVscrollMax - nVscrollPos;
  1242.             break;
  1243.         default:
  1244.             nVscrollInc = 0;
  1245.         }
  1246.         if ((nVscrollInc = max(-nVscrollPos, 
  1247.         min(nVscrollInc, nVscrollMax - nVscrollPos)))!=0) {
  1248.         LONG lComplexity;
  1249.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
  1250.         nVscrollPos += nVscrollInc;
  1251.         scroll_pos.y = nVscrollMax - nVscrollPos;
  1252.         lComplexity = WinScrollWindow(hwnd, 0, nVscrollInc, (PRECTL)NULL, (PRECTL)NULL, 
  1253.             (HRGN)NULLHANDLE, (PRECTL)&rect, 0);
  1254.         WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nVscrollPos), 0);
  1255.         if (lComplexity != RGN_RECT) {
  1256.             WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1257.             WinUpdateWindow(hwnd);
  1258.         }
  1259.         else {
  1260.             /* redraw exposed area */
  1261.             hps = WinGetPS(hwnd);
  1262.                 if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  1263.                     GpiSelectPalette(hps, display.hpal);
  1264.                         WinRealizePalette(hwnd, hps, &ulclr);
  1265.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1266.                     GpiSelectPalette(hps, (HPAL)NULL);
  1267.                 }
  1268.             else
  1269.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1270.             WinReleasePS(hps);
  1271.         }
  1272.         }
  1273.         break;
  1274.     case WM_HSCROLL:
  1275.         switch(SHORT2FROMMP(mp2)) {
  1276.         case SB_LINELEFT:
  1277.             nHscrollInc = -cxClient/16;
  1278.             break;
  1279.         case SB_LINERIGHT:
  1280.             nHscrollInc = cyClient/16;
  1281.             break;
  1282.         case SB_PAGELEFT:
  1283.             nHscrollInc = min(-1,-cxClient);
  1284.             break;
  1285.         case SB_PAGERIGHT:
  1286.             nHscrollInc = max(1,cxClient);
  1287.             break;
  1288. #ifdef NOTUSED
  1289.         case SB_SLIDERTRACK:
  1290.             /* only do this for fast redraw modes */
  1291.             /* these are 8bit/pixel and 1bit/pixel */
  1292.                 if ( (bitmap.depth == 1) ||
  1293.                ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) ) {
  1294.             nHscrollInc = SHORT1FROMMP(mp2) - nHscrollPos;
  1295.             }
  1296.             else
  1297.             nHscrollInc = 0;
  1298. #endif
  1299.         case SB_SLIDERPOSITION:
  1300.             nHscrollInc = SHORT1FROMMP(mp2) - nHscrollPos;
  1301.             break;
  1302.         default:
  1303.             nHscrollInc = 0;
  1304.         }
  1305.         if ((nHscrollInc = max(-nHscrollPos, 
  1306.         min(nHscrollInc, nHscrollMax - nHscrollPos)))!=0) {
  1307.         LONG lComplexity;
  1308.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
  1309.         nHscrollPos += nHscrollInc;
  1310.         scroll_pos.x = nHscrollPos;
  1311.         lComplexity = WinScrollWindow(hwnd, -nHscrollInc, 0, (PRECTL)NULL, (PRECTL)NULL, 
  1312.             (HRGN)NULLHANDLE, (PRECTL)&rect, 0);
  1313.         /* need to send next message BEFORE redrawing, otherwise S3 driver screws up */
  1314.         WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nHscrollPos), 0);
  1315.         if (lComplexity != RGN_RECT) {
  1316.             WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1317.             WinUpdateWindow(hwnd);
  1318.         }
  1319.         else {
  1320.             /* redraw exposed area */
  1321.             hps = WinGetPS(hwnd);
  1322.                 if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  1323.                     GpiSelectPalette(hps, display.hpal);
  1324.                         WinRealizePalette(hwnd, hps, &ulclr);
  1325.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1326.                     GpiSelectPalette(hps, (HPAL)NULL);
  1327.                 }
  1328.             else
  1329.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1330.             WinReleasePS(hps);
  1331.         }
  1332.         }
  1333.         break;
  1334.     case WM_CHAR:    /* process keystrokes here */
  1335.         /* Process only key presses, not key releases */
  1336.         if (SHORT1FROMMP(mp1) & KC_KEYUP)
  1337.             break;
  1338.         if (SHORT1FROMMP(mp1) & KC_VIRTUALKEY) {
  1339.         USHORT vkey = SHORT2FROMMP(mp2);
  1340.         switch(vkey) {
  1341.             case VK_HOME:
  1342.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_TOP));
  1343.                 break;
  1344.             case VK_END:
  1345.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_BOTTOM));
  1346.                 break;
  1347.             case VK_UP:
  1348.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEUP));
  1349.                 break;
  1350.             case VK_DOWN:
  1351.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEDOWN));
  1352.                 break;
  1353.             case VK_PAGEUP:
  1354.                 if (SHORT1FROMMP(mp1) & KC_CTRL)
  1355.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGELEFT));
  1356.              else
  1357.                     WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEUP));
  1358.                 break;
  1359.             case VK_PAGEDOWN:
  1360.                 if (SHORT1FROMMP(mp1) & KC_CTRL)
  1361.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGERIGHT));
  1362.              else
  1363.                     WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEDOWN));
  1364.                 break;
  1365.             case VK_LEFT:
  1366.                 if (SHORT1FROMMP(mp1) & KC_CTRL)
  1367.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGELEFT));
  1368.               else
  1369.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINELEFT));
  1370.                 break;
  1371.             case VK_RIGHT:
  1372.                 if (SHORT1FROMMP(mp1) & KC_CTRL)
  1373.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGERIGHT));
  1374.                 else
  1375.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINERIGHT));
  1376.                 break;
  1377.         }
  1378.         }
  1379.         case WM_BUTTON1DOWN:
  1380.         if (hwnd_modeless) 
  1381.             WinPostMsg(hwnd_modeless, WM_COMMAND, MPFROMSHORT(BB_CLICK), MPFROMLONG(0));
  1382.         break;
  1383.         case WM_BUTTON2DOWN:
  1384.         { float x, y;
  1385.             if (get_cursorpos(&x, &y)) {
  1386.                 zoom = !zoom;
  1387.                 display.zoom_xoffset = x;
  1388.                 display.zoom_yoffset = y;
  1389.             x = (scroll_pos.x+cxClient/2)*72.0/option.xdpi;
  1390.             y = (scroll_pos.y+cyClient/2)*72.0/option.ydpi;
  1391.             transform_point(&x, &y);
  1392.             x *= option.xdpi/72.0;
  1393.             y *= option.ydpi/72.0;
  1394.             display.zoom_xoffset -= (int)(x*72.0/option.zoom_xdpi);
  1395.             display.zoom_yoffset -= (int)(y*72.0/option.zoom_ydpi);
  1396.             }
  1397.             else {
  1398.                 zoom = FALSE;
  1399.             }
  1400.             WinPostMsg(hwnd_bmp, WM_COMMAND, (MPARAM)IDM_ZOOM, MPFROMLONG(0));
  1401.         }
  1402.         break;
  1403.         case WM_MOUSEMOVE:
  1404.         /* track cursor and display coordinates */
  1405.         hps = WinGetPS(hwnd_status);
  1406.         WinFillRect(hps, &info_coord, SYSCLR_BUTTONMIDDLE);
  1407.         cursorpos_paint(hps);
  1408.         WinReleasePS(hps);
  1409.         if (waiting)
  1410.                 WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));
  1411.         else {
  1412.             if (!bitmap.valid)
  1413.                 break;
  1414.                 WinSetPointer(HWND_DESKTOP, hptr_crosshair);
  1415.         }
  1416.         return (MRESULT)TRUE;    /* cursor has been changed */
  1417.         case WM_CLOSE:
  1418.         if (printer.prog.valid) {
  1419.             load_string(IDS_PRINTBUSY, buf, sizeof(buf));
  1420.                 if (message_box(buf, MB_YESNO | MB_ICONQUESTION) != IDYES)
  1421.                 return (MRESULT)0;
  1422.         }
  1423.         break;
  1424.         case DM_DRAGOVER:
  1425.         return DragOver((PDRAGINFO)mp1);
  1426.         case DM_DROP:
  1427.         return Drop((PDRAGINFO)mp1);
  1428.   }
  1429.   /* All messages not handled by the ClientWndProc must be passed */
  1430.   /* along to the Presentation Manager for default processing */
  1431.   return WinDefWindowProc(hwnd, mess, mp1, mp2);
  1432. }
  1433.  
  1434. /* map from a coordinate in points, to a coordinate in pixels */
  1435. /* This is the opposite of the transform part of get_cursorpos */
  1436. /* Used when showing bbox */
  1437. void
  1438. map_pt_to_pixel(float *x, float *y)
  1439. {
  1440.     if (zoom) {
  1441.         /* WARNING - this doesn't cope with EPS Clip */
  1442.         *x = (*x - display.zoom_xoffset) * option.zoom_xdpi / 72.0;
  1443.         *y = (*y - display.zoom_yoffset) * option.zoom_ydpi / 72.0;
  1444.         *x = (*x * 72.0 / option.xdpi);
  1445.         *y = (*y * 72.0 / option.ydpi);
  1446.         itransform_point(x, y);
  1447.         *x = (*x * option.xdpi / 72.0) - scroll_pos.x + display.offset.x;
  1448.         *y = (*y * option.ydpi / 72.0) - scroll_pos.y + display.offset.y;
  1449.     }
  1450.     else {
  1451.         *x = *x - (display.epsf_clipped ? doc->boundingbox[LLX] : 0);
  1452.         *y = *y - (display.epsf_clipped ? doc->boundingbox[LLY] : 0);
  1453.         itransform_point(x, y);
  1454.         *x = *x * option.xdpi/72.0
  1455.           - scroll_pos.x + display.offset.x;
  1456.         *y = *y * option.ydpi/72.0
  1457.           - scroll_pos.y + display.offset.y;
  1458.     }
  1459. }
  1460.  
  1461.  
  1462. /* return coordinates in pts from origin of page */
  1463. /* For Portrait, this is the bottom left */
  1464. /* For rotated pages, this is NOT the bottom left */
  1465. BOOL
  1466. get_cursorpos(float *x, float *y)
  1467. {
  1468. RECTL rect;
  1469. POINTL pt;
  1470.     if (!bitmap.valid)
  1471.         return FALSE;
  1472.     if (!WinQueryPointerPos(HWND_DESKTOP, &pt))
  1473.         return FALSE;
  1474.     WinMapWindowPoints(HWND_DESKTOP, hwnd_bmp, &pt, 1);
  1475.     WinQueryWindowRect(hwnd_bmp, &rect);
  1476.     if (!WinPtInRect(hab, &rect, &pt))
  1477.         return FALSE;
  1478.     *x = scroll_pos.x+pt.x-display.offset.x;
  1479.     *y = scroll_pos.y+pt.y-display.offset.y;
  1480.     transform_cursorpos(x, y);
  1481.     return TRUE;
  1482. }
  1483.  
  1484. void
  1485. cursorpos_paint(HPS hps)
  1486. {
  1487. float x, y;
  1488. POINTL pt;
  1489. char buf[64];
  1490.        if (get_cursorpos(&x, &y)) {
  1491.         switch(option.unit) {
  1492.            case IDM_UNITPT:   
  1493.               sprintf(buf,"%.0f, %.0fpt", x, y);
  1494.           break;
  1495.            case IDM_UNITMM:   
  1496.               sprintf(buf,"%.0f, %.0fmm", x/72*25.4, y/72*25.4);
  1497.           break;
  1498.            case IDM_UNITINCH:   
  1499.               sprintf(buf,"%.1f, %.1fin", x/72, y/72);
  1500.           break;
  1501.         }
  1502.         GpiSetTextAlignment(hps, TA_RIGHT, TA_NORMAL_VERT);
  1503.         pt.x = info_coord.xRight - 1;
  1504.         pt.y = info_page.y;
  1505.             GpiCharStringAt(hps, &pt, strlen(buf), buf);
  1506.       }
  1507. }
  1508.  
  1509. void
  1510. info_paint(HWND hwnd)
  1511. {
  1512. HPS ps;
  1513. RECTL rect;
  1514. POINTL pt;
  1515. int i;
  1516. char *p;
  1517. char buf[MAXSTR];
  1518. char fmt[MAXSTR];
  1519.         ps = WinBeginPaint(hwnd, (ULONG)0, &rect);
  1520.     /* draw background */
  1521.     WinFillRect(ps, &rect, SYSCLR_BUTTONMIDDLE);
  1522.     GpiSetColor(ps, SYSCLR_BUTTONDARK);
  1523.     pt.x = 0; pt.y = 0;
  1524.     GpiMove(ps, &pt);
  1525.     pt.x = statusbar.x - 1;
  1526.     GpiLine(ps, &pt);
  1527.     pt.y = statusbar.y - 1;
  1528.     GpiLine(ps, &pt);
  1529.     GpiSetColor(ps, SYSCLR_BUTTONLIGHT);
  1530.     pt.x = 0;
  1531.     GpiLine(ps, &pt);
  1532.     pt.y = 0;
  1533.     GpiLine(ps, &pt);
  1534.     GpiSetColor(ps, SYSCLR_BUTTONDEFAULT);
  1535.  
  1536.     /* write file information */
  1537.     if (psfile.name[0] != '\0') {
  1538.         i = load_string(IDS_FILE, buf, sizeof(buf));
  1539.         if ( (p = strrchr(psfile.name, '\\')) == (char *)NULL )
  1540.         p = psfile.name;
  1541.         else
  1542.         p++;
  1543.         strcat(buf, p);
  1544.         GpiCharStringAt(ps, &info_file, strlen(buf), buf);
  1545.         if (waiting) {
  1546. /*
  1547.         i = load_string(IDS_WAIT, buf, sizeof(buf));
  1548.             GpiCharStringAt(ps, &info_page, strlen(buf), buf);
  1549. */
  1550.             GpiCharStringAt(ps, &info_page, strlen(szWait), szWait);
  1551.         }
  1552.         else {
  1553.           if (doc!=(PSDOC *)NULL) {
  1554.         int n = map_page(psfile.pagenum - 1);
  1555.         i = load_string(IDS_PAGEINFO, fmt, sizeof(fmt));
  1556.         if (doc->pages)
  1557.             sprintf(buf, fmt, doc->pages[n].label ? doc->pages[n].label : " ",psfile.pagenum,  doc->numpages);
  1558.         else
  1559.             sprintf(buf, fmt, " " ,psfile.pagenum,  doc->numpages);
  1560.         if (zoom)
  1561.             strcat(buf, "  Zoomed");
  1562.             GpiCharStringAt(ps, &info_page, strlen(buf), buf);
  1563.           }
  1564.           else {
  1565.         if (is_pipe_done())
  1566.             i = load_string(IDS_NOMORE, buf, sizeof(buf));
  1567.         else {
  1568.             i = load_string(IDS_PAGE, buf, sizeof(buf));
  1569.             sprintf(buf+i, "%d", psfile.pagenum);
  1570.         }
  1571.             GpiCharStringAt(ps, &info_page, strlen(buf), buf);
  1572.           }
  1573.           /* show coordinate */
  1574.           cursorpos_paint(ps);
  1575.         }
  1576.     }
  1577.     else {
  1578.         i = load_string(IDS_NOFILE, buf, sizeof(buf));
  1579.         GpiCharStringAt(ps, &info_file, strlen(buf), buf);
  1580.         if (waiting) {
  1581. /*
  1582.         i = load_string(IDS_WAIT, buf, sizeof(buf));
  1583.             GpiCharStringAt(ps, &info_page, strlen(buf), buf);
  1584. */
  1585.             GpiCharStringAt(ps, &info_page, strlen(szWait), szWait);
  1586.         }
  1587.     }
  1588.     WinEndPaint(hwnd);
  1589. }
  1590.  
  1591.  
  1592. /* Status Bar Window Proc */
  1593. MRESULT EXPENTRY StatusWndProc(HWND hwnd, ULONG mess, 
  1594.             MPARAM mp1, MPARAM mp2)
  1595. {
  1596.   HPS ps;
  1597.   RECTL rect;
  1598.   POINTL pt;
  1599.   switch (mess) {
  1600.     case WM_CREATE:
  1601.     {
  1602.     FONTMETRICS fm;
  1603.     POINTL char_size;
  1604.     ps = WinGetPS(hwnd);
  1605.     GpiQueryFontMetrics(ps, sizeof(FONTMETRICS), &fm);
  1606.     char_size.y = fm.lMaxAscender + fm.lMaxDescender + fm.lExternalLeading + 2;
  1607.     char_size.x = fm.lAveCharWidth;
  1608.     statusbar.y = char_size.y + 2;
  1609.     info_file.x = 2;
  1610.     info_file.y = fm.lMaxDescender + 3;
  1611.     info_coord.xLeft = 23 * char_size.x;
  1612.     info_coord.xRight = 38 * char_size.x;
  1613.     info_coord.yTop = char_size.y - 1;
  1614.     info_coord.yBottom = 1;
  1615.     info_page.x = 40 * char_size.x + 2;
  1616.     info_page.y = fm.lMaxDescender + 3;
  1617. /*
  1618.     WinFillRect(ps, SYSCLR_BUTTONMIDDLE);
  1619. */
  1620.     WinReleasePS(ps);
  1621.     }
  1622.     break;
  1623.     case WM_PAINT:
  1624.     info_paint(hwnd);
  1625.     return 0;
  1626.   }
  1627.   return WinDefWindowProc(hwnd, mess, mp1, mp2);
  1628. }
  1629.  
  1630.  
  1631. void
  1632. shade_button(HPS hps, struct button *bp, BOOL down)
  1633. {
  1634. POINTL pt;
  1635.     /* draw button shading */
  1636.     if (down)
  1637.         GpiSetColor(hps, SYSCLR_BUTTONLIGHT);
  1638.     else
  1639.         GpiSetColor(hps, SYSCLR_BUTTONDARK);
  1640.     pt.x = bp->rect.xLeft; 
  1641.     pt.y = bp->rect.yBottom;
  1642.     GpiMove(hps, &pt);
  1643.     pt.x = bp->rect.xRight - 1;
  1644.     GpiLine(hps, &pt);
  1645.     pt.y = bp->rect.yTop - 1;
  1646.     GpiLine(hps, &pt);
  1647.     if (down)
  1648.         GpiSetColor(hps, SYSCLR_BUTTONDARK);
  1649.     else
  1650.         GpiSetColor(hps, SYSCLR_BUTTONLIGHT);
  1651.     pt.x = bp->rect.xLeft;
  1652.     GpiLine(hps, &pt);
  1653.     pt.y = bp->rect.yBottom;
  1654.     GpiLine(hps, &pt);
  1655.     GpiSetColor(hps, SYSCLR_BUTTONDEFAULT);
  1656. }
  1657.  
  1658. void
  1659. size_buttons(PPOINTL ppt)
  1660. {
  1661.   struct button *bp;
  1662.   int i = 0;
  1663.   if (option.button_show) {
  1664.     for (bp = buttonhead; bp != (struct button *)NULL; bp = bp->next) {
  1665.     bp->rect.xLeft = i * button_shift.x;
  1666.     bp->rect.yBottom = ppt->y - button_size.y - i * button_shift.y;
  1667.     bp->rect.xRight = bp->rect.xLeft + button_size.x;
  1668.     bp->rect.yTop = bp->rect.yBottom + button_size.y;
  1669.         i++;
  1670.     }
  1671.   }
  1672. }
  1673.  
  1674. /* Button Bar Window Proc */
  1675. MRESULT EXPENTRY ButtonWndProc(HWND hwnd, ULONG mess, 
  1676.             MPARAM mp1, MPARAM mp2)
  1677. {
  1678.   HPS hps;
  1679.   RECTL rect;
  1680.   POINTL pt;
  1681.   struct button *bp;
  1682.   switch (mess) {
  1683.     case WM_SIZE:
  1684.     /* reposition buttons */
  1685.     pt.x = SHORT1FROMMP(mp2);
  1686.     pt.y = SHORT2FROMMP(mp2);
  1687.         size_buttons(&pt);
  1688.     WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1689.     break;
  1690.     case WM_BUTTON1DOWN:
  1691.     pt.x = SHORT1FROMMP(mp1);
  1692.     pt.y = SHORT2FROMMP(mp1);
  1693.     for (bp = buttonhead; bp != (struct button *)NULL; bp = bp->next) {
  1694.         if (WinPtInRect(hab, &(bp->rect), &pt)) {
  1695.         button_current = bp;
  1696.         button_down = TRUE;
  1697.         hps = WinGetPS(hwnd);
  1698.         shade_button(hps, bp, TRUE);
  1699.         WinReleasePS(hps);
  1700.             WinSetCapture(HWND_DESKTOP, hwnd);
  1701.         break;
  1702.         }
  1703.     }
  1704.     break;
  1705.     case WM_BUTTON1UP:
  1706.     pt.x = SHORT1FROMMP(mp1);
  1707.     pt.y = SHORT2FROMMP(mp1);
  1708.     bp = button_current;
  1709.     if (bp != (struct button *)NULL) {
  1710.         hps = WinGetPS(hwnd);
  1711.         shade_button(hps, bp, FALSE);
  1712.         WinReleasePS(hps);
  1713.         if (WinPtInRect(hab, &(bp->rect), &pt)) {
  1714.             WinPostMsg(hwnd_bmp, WM_COMMAND, MPFROMSHORT(bp->id), MPFROMLONG(0));
  1715.         }
  1716.     }
  1717.     WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  1718.     WinInvalidateRect(hwnd_status, NULL, FALSE);
  1719.     WinUpdateWindow(hwnd_status);
  1720.     button_info = NULL;
  1721.     button_current = NULL;
  1722.     button_down = FALSE;
  1723.     break;
  1724.     case WM_MOUSEMOVE:
  1725.     pt.x = SHORT1FROMMP(mp1);
  1726.     pt.y = SHORT2FROMMP(mp1);
  1727.     bp = button_current;
  1728.     if (bp != (struct button *)NULL) {
  1729.         if (button_down && !WinPtInRect(hab, &(bp->rect), &pt)) {
  1730.         button_down = FALSE;
  1731.         hps = WinGetPS(hwnd);
  1732.         shade_button(hps, bp, FALSE);
  1733.         WinReleasePS(hps);
  1734.         }
  1735.         else if (!button_down && WinPtInRect(hab, &(bp->rect), &pt)) {
  1736.         button_down = TRUE;
  1737.         hps = WinGetPS(hwnd);
  1738.         shade_button(hps, bp, TRUE);
  1739.         WinReleasePS(hps);
  1740.         }
  1741.     }
  1742.     else {
  1743.         /* track cursor and display button function */
  1744.         char buf[64];
  1745.         /* find button */
  1746.         for (bp = buttonhead; bp != (struct button *)NULL; bp = bp->next) {
  1747.           if (WinPtInRect(hab, &(bp->rect), &pt)) {
  1748.         break;
  1749.           }
  1750.         }
  1751.         if (bp != button_info) {
  1752.           button_info = bp;
  1753.           if (bp != (struct button *)NULL) {
  1754.         if (WinQueryCapture(HWND_DESKTOP) != hwnd)
  1755.                 WinSetCapture(HWND_DESKTOP, hwnd); /* track all mouse movements */
  1756.             /* erase page area of status bar */
  1757.             hps = WinGetPS(hwnd_status);
  1758.             rect.xLeft = info_file.x;
  1759.             rect.xRight = statusbar.x - 1;
  1760.             rect.yBottom = info_coord.yBottom;
  1761.             rect.yTop = info_coord.yTop;
  1762.             WinFillRect(hps, &rect, SYSCLR_BUTTONMIDDLE);
  1763.         load_string(bp->id, buf, sizeof(buf));
  1764.                 GpiCharStringAt(hps, &info_file, strlen(buf), buf);
  1765.             WinReleasePS(hps);
  1766.           }
  1767.           else {
  1768.             WinSetCapture(HWND_DESKTOP, NULLHANDLE);  /* release capture */
  1769.         /* put statusbar back to normal */
  1770.             WinInvalidateRect(hwnd_status, NULL, FALSE);
  1771.           WinUpdateWindow(hwnd_status);
  1772.           }
  1773.         }
  1774.     }
  1775.     break;
  1776.     case WM_PAINT:
  1777.     hps = WinBeginPaint(hwnd, (ULONG)0, &rect);
  1778.     /* draw background */
  1779.     WinFillRect(hps, &rect, SYSCLR_BUTTONMIDDLE);
  1780.     GpiSetColor(hps, SYSCLR_BUTTONDARK);
  1781.     pt.x = buttonbar.x - 1; pt.y = 0;
  1782.     GpiMove(hps, &pt);
  1783.     pt.y = buttonbar.y - 1;
  1784.     GpiLine(hps, &pt);
  1785.     GpiSetColor(hps, SYSCLR_BUTTONLIGHT);
  1786.     pt.x = 0;
  1787.     GpiLine(hps, &pt);
  1788.     pt.y = 0;
  1789.     GpiLine(hps, &pt);
  1790.     GpiSetColor(hps, SYSCLR_BUTTONDEFAULT);
  1791.     for (bp = buttonhead; bp != (struct button *)NULL; bp = bp->next) {
  1792.         if (bp->hbitmap) {
  1793.         /* draw bitmap */
  1794.         pt.x = bp->rect.xLeft;
  1795.         pt.y = bp->rect.yBottom;
  1796.         WinDrawBitmap(hps, bp->hbitmap, NULL, &pt, 0, 0, DBM_NORMAL);
  1797.         }
  1798.         else {
  1799.         /* draw button text */
  1800.         pt.x = (bp->rect.xLeft + bp->rect.xRight)/2;
  1801.         pt.y = (bp->rect.yBottom + bp->rect.yTop)/2;
  1802.             GpiSetTextAlignment(hps, TA_CENTER, TA_HALF);
  1803.                 GpiCharStringAt(hps, &pt, strlen(bp->str), bp->str);
  1804.         }
  1805.         shade_button(hps, bp, FALSE);
  1806.     }
  1807.     WinEndPaint(hwnd);
  1808.     return 0;
  1809.   }
  1810.   return WinDefWindowProc(hwnd, mess, mp1, mp2);
  1811. }
  1812.  
  1813. /* subclassed Frame Window Procedure */
  1814. MRESULT EXPENTRY FrameWndProc(HWND hwnd, ULONG mess, 
  1815.             MPARAM mp1, MPARAM mp2)
  1816. {
  1817. MRESULT mr;
  1818. int sCount;
  1819. PSWP pswpNew, pswpClient, pswp;
  1820.  
  1821.   switch(mess) {
  1822.     case WM_HELP:
  1823.     /* HM_DISPLAY_HELP is unreliable for HM_PANELNAME so we lookup */
  1824.     /* the id ourselves and use HM_RESOURCEID */
  1825.     {
  1826.     HELPIDX *hidx;
  1827.       for (hidx = helpidx; hidx->id != 0; hidx++) {
  1828.         if (strcmp(hidx->name, szHelpTopic)==0) {
  1829.         WinSendMsg(hwnd_help, HM_DISPLAY_HELP, MPFROMSHORT(hidx->id), MPFROMSHORT(HM_RESOURCEID));
  1830.         continue;
  1831.         }
  1832.       }
  1833.     }
  1834.     return 0;
  1835.     case WM_CALCFRAMERECT:
  1836.     mr =  (*OldFrameWndProc)(hwnd, mess, mp1, mp2);
  1837.     /* calculate position of client rectangle */
  1838.     if (mr && mp2) {
  1839.         ((PRECTL)mp1)->yTop -= statusbar.y;
  1840.         if (option.button_show)
  1841.             ((PRECTL)mp1)->xLeft += buttonbar.x;
  1842.     }
  1843.     return mr;
  1844.     case WM_FORMATFRAME:
  1845.     /* reformat frame to make room for status bar */
  1846.     mr =  (*OldFrameWndProc)(hwnd, mess, mp1, mp2);
  1847.     sCount = (int)mr;
  1848.     pswp = (PSWP)mp1;
  1849.     pswpClient = (PSWP)mp1 + sCount - 1;
  1850.     pswpNew = pswpClient + 1;
  1851.     *pswpNew = *pswpClient;
  1852.     pswpNew->hwnd = WinWindowFromID(hwnd, ID_STATUSBAR);
  1853.     pswpNew->cy = statusbar.y;
  1854.     pswpClient->cy -= pswpNew->cy;
  1855.     pswpNew->y = pswpClient->y + pswpClient->cy;
  1856.     pswp[FID_VERTSCROLL - FID_SYSMENU].cy -= pswpNew->cy;
  1857.     pswpNew->x = pswp[FID_MENU - FID_SYSMENU].x;
  1858.     pswpNew->cx = pswp[FID_MENU - FID_SYSMENU].cx;
  1859.     statusbar.x = pswpNew->cx;
  1860.     sCount++;
  1861.     /* reformat frame to make room for button bar */
  1862.     pswpNew++;
  1863.     *pswpNew = *pswpClient;
  1864.     pswpNew->hwnd = WinWindowFromID(hwnd, ID_BUTTONBAR);
  1865.     pswpNew->x = pswpClient->x;
  1866.         pswpNew->cx = buttonbar.x;
  1867.     pswpNew->y = pswpClient->y;
  1868.     pswpNew->cy = pswpClient->cy;
  1869.     buttonbar.y = pswpNew->cy;
  1870.     pswpNew->fl &= ~(SWP_SHOW | SWP_HIDE);
  1871.     sCount++;
  1872.     if (option.button_show) {
  1873.         pswpClient->x += buttonbar.x;
  1874.         pswpClient->cx -= buttonbar.x;
  1875.         pswpNew->fl |= SWP_SHOW;
  1876.         /* following is a kludge because ButtonWndProc is receiving WM_SIZE
  1877.            messages in reverse order to WM_FORMATFRAME here! */
  1878.         WinPostMsg(hwnd_button, WM_SIZE, 
  1879.         MPFROM2SHORT(pswpNew->cx, pswpNew->cy), 
  1880.         MPFROM2SHORT(pswpNew->cx, pswpNew->cy));
  1881.     }
  1882.     else {
  1883.         pswpNew->fl |= SWP_HIDE;
  1884.     }
  1885.     return (MRESULT)sCount;
  1886.     case WM_QUERYFRAMECTLCOUNT:
  1887.     mr =  (*OldFrameWndProc)(hwnd, mess, mp1, mp2);
  1888.         sCount = (int)mr;
  1889.         sCount+=2;
  1890.     return (MRESULT)sCount;
  1891.   }
  1892.   return (*OldFrameWndProc)(hwnd, mess, mp1, mp2);
  1893. }
  1894.  
  1895. MRESULT
  1896. DragOver(PDRAGINFO pDragInfo)
  1897. {
  1898. int cItems, i;
  1899. PDRAGITEM pditem;
  1900. USHORT usDrop, usDefaultOp;
  1901. char dtype[256];
  1902. char drmf[256];
  1903.     if (!DrgAccessDraginfo(pDragInfo))
  1904.         return MRFROM2SHORT(DOR_NODROPOP, 0);
  1905.     switch(pDragInfo->usOperation) {
  1906.         case DO_DEFAULT:
  1907.         case DO_COPY:
  1908.         usDrop = DOR_DROP;
  1909.         usDefaultOp = DO_COPY;
  1910.         break;
  1911.         default:
  1912.         case DO_UNKNOWN:
  1913.         case DO_MOVE:
  1914.         DrgFreeDraginfo(pDragInfo);
  1915.         return MRFROM2SHORT(DOR_NODROPOP, 0);
  1916.     }
  1917.     
  1918.     cItems = DrgQueryDragitemCount(pDragInfo);
  1919.     for (i=0; i<cItems; i++) {
  1920.         pditem = DrgQueryDragitemPtr(pDragInfo, i);
  1921.         DrgQueryStrName(pditem->hstrType, sizeof(dtype)-1, dtype);
  1922.         DrgQueryStrName(pditem->hstrRMF, sizeof(drmf)-1, drmf);
  1923.         if (pditem->fsSupportedOps & DO_COPYABLE)  {
  1924.             if ( DrgVerifyRMF(pditem, "DRM_OS2FILE", "DRF_TEXT") )
  1925.                 usDrop = DOR_DROP;
  1926.         else
  1927.                 usDrop = DOR_NEVERDROP;
  1928.         }
  1929.         else {
  1930.         usDrop = DOR_NODROPOP;
  1931.         }
  1932.     }
  1933.     DrgFreeDraginfo(pDragInfo);
  1934.     return MRFROM2SHORT(usDrop, usDefaultOp);
  1935. }
  1936.  
  1937. MRESULT
  1938. Drop(PDRAGINFO pDragInfo)
  1939. {
  1940. int cItems, i;
  1941. DRAGITEM dragitem;
  1942. USHORT usDrop, usDefaultOp;
  1943. char dirname[MAXSTR];
  1944. char filename[MAXSTR];
  1945. char *dragname;
  1946. int length;
  1947. HPS hps;
  1948. POINTL pt;
  1949.     if (!DrgAccessDraginfo(pDragInfo))
  1950.         return MRFROM2SHORT(DOR_NODROPOP, 0);
  1951.     cItems = DrgQueryDragitemCount(pDragInfo);
  1952.     for (i=0; i<cItems; i++) {
  1953.         DrgQueryDragitem(pDragInfo, sizeof(dragitem), &dragitem, i);
  1954.         length = DrgQueryStrName(dragitem.hstrContainerName, sizeof(dirname), dirname);
  1955.         length += DrgQueryStrName(dragitem.hstrSourceName, sizeof(filename), filename);
  1956.         dragname = malloc(length+1);
  1957.         strcpy(dragname, dirname);
  1958.         strcat(dragname, filename);
  1959.         WinPostMsg(hwnd_bmp, WM_COMMAND, (MPARAM)IDM_DROP, MPFROMP(dragname));    /* mp2 is not strictly correct */
  1960.     }
  1961.     DrgDeleteDraginfoStrHandles(pDragInfo);
  1962.     DrgFreeDraginfo(pDragInfo);
  1963.     return (MRESULT)0;
  1964. }
  1965.  
  1966.