1 /****************************************************************************
2 
3     PROGRAM: gnupmdrv
4 
5     Outboard PM driver for GNUPLOT 3.3
6 
7     MODULE:  print.c -- support for printing graphics under OS/2
8 
9 ****************************************************************************/
10 
11 /* PM driver for GNUPLOT */
12 
13 /*[
14  * Copyright 1992, 1993, 1998, 2004 Roger Fearick
15  *
16  * Permission to use, copy, and distribute this software and its
17  * documentation for any purpose with or without fee is hereby granted,
18  * provided that the above copyright notice appear in all copies and
19  * that both that copyright notice and this permission notice appear
20  * in supporting documentation.
21  *
22  * Permission to modify the software is granted, but not the right to
23  * distribute the complete modified source code.  Modifications are to
24  * be distributed as patches to the released version.  Permission to
25  * distribute binaries produced by compiling modified sources is granted,
26  * provided you
27  *   1. distribute the corresponding source modifications from the
28  *    released version in the form of a patch file along with the binaries,
29  *   2. add special version identification to distinguish your version
30  *    in addition to the base release version number,
31  *   3. provide your name and address as the primary contact for the
32  *    support of your modified version, and
33  *   4. retain our contact information in regard to use of the base
34  *    software.
35  * Permission to distribute the released version of the source code along
36  * with corresponding source modifications in the form of a patch file is
37  * granted with same provisions 2 through 4 for binary distributions.
38  *
39  * This software is provided "as is" without express or implied warranty
40  * to the extent permitted by applicable law.
41 ]*/
42 
43 /*
44  * AUTHOR
45  *
46  *   Gnuplot driver for OS/2:  Roger Fearick
47  */
48 
49 #define INCL_SPLDOSPRINT
50 #define INCL_DOSPROCESS
51 #define INCL_DOSSEMAPHORES
52 #define INCL_DEV
53 #define INCL_SPL
54 #define INCL_PM
55 #define INCL_WIN
56 #include <os2.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <process.h>
61 #include "gnupmdrv.h"
62 
63 #define   GNUPAGE   4096        /* size of gnuplot page in pixels (driver dependent) */
64 
65 
66 typedef struct {            /* for print thread parameters */
67     HWND  hwnd ;
68     HDC   hdc ;                 /* printer device context */
69     HPS   hps ;                 /* screen PS to be printed */
70     char  szPrintFile[256] ;    /* file for printer output if not to printer */
71     PQPRINT pqp ;       /* print queue info */
72     } PRINTPARAMS ;
73 
74 static struct {
75     long    lTech ;     // printer technology
76     long    lVer ;      // driver version
77     long    lWidth ;    // page width in pels
78     long    lHeight ;   // page height in pels
79     long    lWChars ;   // page width in chars
80     long    lHChars ;   // page height in chars
81     long    lHorRes ;   // horizontal resolution pels / metre
82     long    lVertRes ;  // vertical resolution pels / metre
83     } prCaps ;
84 
85 //static PDRIVDATA    pdriv = NULL ;
86 static DRIVDATA     driv = {sizeof( DRIVDATA) } ;
87 static char         szPrintFile[CCHMAXPATHCOMP] = {0} ;
88 static DEVOPENSTRUC devop ;
89 
90 ULONG GetPrinters( PPRQINFO3 *, ULONG *  ) ;
91 int FindPrinter( char *, PPRQINFO3  ) ;
92 HMF     CopyToMetaFile( HPS ) ;
93 static void    ThreadPrintPage( ) ;
94 
PrintCmdProc(HWND hWnd,ULONG msg,MPARAM mp1,MPARAM mp2)95 MPARAM PrintCmdProc( HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
96 /*
97 **  Handle messages for print commands for 1- and 2-d spectra
98 ** (i.e for the appropriate 1-and 2-d child windows )
99 */
100     {
101     static PRINTPARAMS tp ;
102     static char szBusy[] = "Busy - try again later" ;
103     static char szStart[] = "Printing started" ;
104     static HEV semPrint = 0L ;
105     static HWND hwndCancel = NULLHANDLE ;
106     char szTemp[32] ;
107     unsigned short lErr ;
108     TID tid ;
109     char *pszMess;
110 
111     if( semPrint == 0L ) {
112         DosCreateMutexSem( NULL, &semPrint, 0L, 0L ) ;
113         }
114 
115     switch( msg ) {
116 
117         case WM_USER_PRINT_BEGIN:
118 
119             if( DosRequestMutexSem( semPrint, SEM_IMMEDIATE_RETURN ) != 0 ) {
120                 pszMess = szBusy ;
121                 WinMessageBox( HWND_DESKTOP,
122                                hWnd,
123                                pszMess,
124                                APP_NAME,
125                                0,
126                                MB_OK | MB_ICONEXCLAMATION ) ;
127                 }
128             else {
129                 pszMess = szStart ;
130                 tp.hwnd = hWnd ;
131                 tp.pqp = (PQPRINT) mp1 ;
132                 tp.hps = (HPS) mp2 ;
133                 strcpy( tp.szPrintFile, szPrintFile ) ;
134                 tid = _beginthread( ThreadPrintPage, NULL, 32768, &tp ) ;
135                 hwndCancel = WinLoadDlg( HWND_DESKTOP,
136                                          hWnd,
137                                          (PFNWP)CancelPrintDlgProc,
138                                          0L,
139                                          ID_PRINTSTOP,
140                                          NULL ) ;
141                 }
142             break ;
143 
144 
145         case WM_USER_PRINT_OK :
146 
147             if( hwndCancel != NULLHANDLE ) {
148                 WinDismissDlg( hwndCancel, 0 ) ;
149                 hwndCancel = NULLHANDLE ;
150                 }
151              DosReleaseMutexSem( semPrint ) ;
152              break ;
153 
154         case WM_USER_DEV_ERROR :
155 
156             if( hwndCancel != NULLHANDLE ) {
157                 WinDismissDlg( hwndCancel, 0 ) ;
158                 hwndCancel = NULLHANDLE ;
159                 }
160             lErr = ERRORIDERROR( (ERRORID) mp1 ) ;
161             sprintf( szTemp, "Dev error: %d %x", lErr, lErr ) ;
162             WinMessageBox( HWND_DESKTOP,
163                            hWnd,
164                            szTemp,
165                            APP_NAME,
166                            0,
167                            MB_OK | MB_ICONEXCLAMATION ) ;
168              DosReleaseMutexSem( semPrint ) ;
169              break ;
170 
171         case WM_USER_PRINT_ERROR :
172 
173             if( hwndCancel != NULLHANDLE ) {
174                 WinDismissDlg( hwndCancel, 0 ) ;
175                 hwndCancel = NULLHANDLE ;
176                 }
177             lErr = ERRORIDERROR( (ERRORID) mp1 ) ;
178             sprintf( szTemp, "Print error: %d %x", lErr, lErr ) ;
179             WinMessageBox( HWND_DESKTOP,
180                            hWnd,
181                            szTemp,
182                            APP_NAME,
183                            0,
184                            MB_OK | MB_ICONEXCLAMATION ) ;
185              DosReleaseMutexSem( semPrint ) ;
186              break ;
187 
188         case WM_USER_PRINT_CANCEL :
189 
190              DevEscape( tp.hdc, DEVESC_ABORTDOC, 0L, NULL, NULL, NULL ) ;
191              break ;
192 
193 
194         case WM_USER_PRINT_QBUSY :
195 
196             return( (MPARAM)DosRequestMutexSem( semPrint, SEM_IMMEDIATE_RETURN ) ) ;
197 
198         default : break ;
199         }
200 
201     return 0L ;
202     }
203 
SetupPrinter(HWND hwnd,PQPRINT pqp)204 int SetupPrinter( HWND hwnd, PQPRINT pqp )
205 /*
206 **  Set up the printer
207 **
208 */
209     {
210     HDC hdc ;
211     float flXFrac, flYFrac;
212           /* check that printer is still around .. */
213     if( FindPrinter( pqp->szPrinterName, pqp->piPrinter ) != 0 ) return 0 ;
214           /* get printer capabilities */
215     if( (hdc = OpenPrinterDC( WinQueryAnchorBlock( hwnd ), pqp, OD_INFO, NULL )) != DEV_ERROR ) {
216         DevQueryCaps( hdc, CAPS_TECHNOLOGY, (long)sizeof(prCaps)/sizeof(long), (PLONG)&prCaps ) ;
217         DevCloseDC( hdc ) ;
218         pqp->xsize = (float)100.0* (float) prCaps.lWidth / (float) prCaps.lHorRes ; // in cm
219         pqp->ysize = (float)100.0* (float) prCaps.lHeight / (float) prCaps.lVertRes ; // in cm
220         flXFrac = pqp->xfrac ;
221         flYFrac = pqp->yfrac ;
222         pqp->szFilename[0] = 0 ;
223         szPrintFile[0] = 0 ;
224         pqp->caps  = prCaps.lTech & (CAPS_TECH_VECTOR_PLOTTER|CAPS_TECH_POSTSCRIPT) ?
225                    QP_CAPS_FILE : QP_CAPS_NORMAL ;
226         if( WinDlgBox( HWND_DESKTOP,
227                       hwnd,
228                     (PFNWP)QPrintDlgProc,
229                     0L,
230                     ID_QPRINT,
231                     pqp ) == DID_OK ) {
232           if( pqp->caps & QP_CAPS_FILE ) {
233               if( pqp->szFilename[0] != 0 ) strcpy( szPrintFile, pqp->szFilename ) ;
234               }
235           return 1 ;
236           }
237         pqp->xfrac = flXFrac ;
238         pqp->yfrac = flYFrac ;
239         }
240 
241     return 0 ;
242     }
243 
SetPrinterMode(HWND hwnd,PQPRINT pqp)244 int SetPrinterMode( HWND hwnd, PQPRINT pqp )
245 /*
246 **  call up printer driver's own setup dialog box
247 **
248 **  returns :  -1 if error
249 **              0 if no settable modes
250 **              1 if OK
251 */
252     {
253     HAB hab ;
254     LONG lBytes ;
255     PPRQINFO3 pinfo = pqp->piPrinter ;
256 
257     hab = WinQueryAnchorBlock( hwnd ) ;
258     driv.szDeviceName[0]='\0' ;
259     lBytes = DevPostDeviceModes( hab,
260                                  NULL,
261                                  devop.pszDriverName,
262                                  pinfo->pDriverData->szDeviceName,
263                                  //driv.szDeviceName,
264                                  NULL,
265                                  DPDM_POSTJOBPROP ) ;
266     if( lBytes > 0L ) {
267             /* if we have old pdriv data, and if it's for the same printer,
268                keep it to retain user's current settings, else get new */
269         if( pqp->pdriv != NULL
270         && strcmp( pqp->pdriv->szDeviceName, pinfo->pDriverData->szDeviceName ) != 0 ) {
271             free( pqp->pdriv ) ;
272             pqp->pdriv = NULL ;
273             }
274         if( pqp->pdriv == NULL ) {
275             if( lBytes < pinfo->pDriverData->cb ) lBytes = pinfo->pDriverData->cb ;
276             pqp->pdriv = malloc( lBytes ) ;
277             pqp->cbpdriv = lBytes ;
278             memcpy( pqp->pdriv, pinfo->pDriverData, lBytes ) ;
279             }
280         strcpy( driv.szDeviceName, pqp->pdriv->szDeviceName ) ;
281 //        pqp->pdriv->szDeviceName[0] = '\0' ;  /* to check if 'cancel' selected */
282         lBytes = DevPostDeviceModes( hab,
283                                      pqp->pdriv,
284                                      devop.pszDriverName,
285                                      driv.szDeviceName,
286                                      NULL,
287                                      DPDM_POSTJOBPROP ) ;
288         if( lBytes != 1 /*pqp->pdriv->szDeviceName[0] == '\0'*/ ) {  /* could be: 'cancel' selected */
289             pqp->cbpdriv = lBytes = 0 ;
290             free(pqp->pdriv ) ;   /* is this right ???? */
291             pqp->pdriv = NULL ;
292             }
293         }
294     return ( (int) lBytes ) ;
295     }
296 
ThreadPrintPage(PRINTPARAMS * ptp)297 static void ThreadPrintPage( PRINTPARAMS *ptp )
298 /*
299 **  thread to set up printer DC and print page
300 **
301 **  Input: THREADPARAMS *ptp -- pointer to thread data passed by beginthread
302 **
303 */
304     {
305     HAB         hab ;       // thread anchor block nandle
306     HDC         hdc ;       // printer device context handle
307     HPS         hps ;       // presentation space handle
308     SHORT       msgRet ;    // message posted prior to return (end of thread)
309     SIZEL       sizPage ;   // size of page for creation of presentation space
310     LONG        alPage[2] ; // actual size of printer page in pixels
311     RECTL       rectPage ;  // viewport on page into which we draw
312     LONG        lColors ;
313     char        *szPrintFile ;
314     HMF         hmf ;
315     LONG        alOpt[9] ;
316     HPS         hpsSc ;
317     hab = WinInitialize( 0 ) ;
318 
319     szPrintFile = ptp->szPrintFile[0] == '\0' ? NULL : ptp->szPrintFile ;
320 
321     if( (hdc = OpenPrinterDC( hab, ptp->pqp, 0L, szPrintFile )) != DEV_ERROR ) {
322 
323             // create presentation space for printer
324 
325         ptp->hdc = hdc ;
326         hmf = CopyToMetaFile( ptp->hps ) ;
327         hpsSc = ptp->hps ;
328 
329         sizPage.cx = GNUXPAGE;
330         sizPage.cy = GNUYPAGE;
331         hps = GpiCreatePS( hab,
332                            hdc,
333                            &sizPage,
334                            PU_HIMETRIC | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC ) ;
335 
336         DevQueryCaps( hdc, CAPS_WIDTH, 2L, alPage ) ;
337         DevQueryCaps( hdc, CAPS_PHYS_COLORS, 1L, &lColors ) ;
338         rectPage.xLeft = 0L ;
339         rectPage.xRight = alPage[0] ;
340         rectPage.yTop = alPage[1] ;//alPage[1]*(1.0-flYFrac) ;
341         rectPage.yBottom = 0L ; //  = alPage[1] ;
342 
343         {
344         double ratio = 1.560 ;
345         double xs = rectPage.xRight - rectPage.xLeft ;
346         double ys = rectPage.yTop - rectPage.yBottom ;
347         if( ys > xs/ratio ) { /* reduce ys to fit */
348             rectPage.yTop = rectPage.yBottom + (int)(xs/ratio) ;
349             }
350         else if( ys < xs/ratio ) { /* reduce xs to fit */
351             rectPage.xRight = rectPage.xLeft + (int)(ys*ratio) ;
352             }
353         }
354 
355         rectPage.xRight = rectPage.xRight*ptp->pqp->xfrac ;
356         rectPage.yTop = rectPage.yTop*ptp->pqp->yfrac ;//alPage[1]*(1.0-flYFrac) ;
357 
358         {
359         double ratio = 1.560 ;
360         double xs = rectPage.xRight - rectPage.xLeft ;
361         double ys = rectPage.yTop - rectPage.yBottom ;
362         if( ys > xs/ratio ) { /* reduce ys to fit */
363             rectPage.yTop = rectPage.yBottom + (int)(xs/ratio) ;
364             }
365         else if( ys < xs/ratio ) { /* reduce xs to fit */
366             rectPage.xRight = rectPage.xLeft + (int)(ys*ratio) ;
367             }
368         }
369 
370 
371             // start printing
372 
373         if( DevEscape( hdc,
374                        DEVESC_STARTDOC,
375                        7L,
376                        APP_NAME,
377                        NULL,
378                        NULL ) != DEVESC_ERROR ) {
379             char buff[256] ;
380             int rc;
381 
382             rc = GpiSetPageViewport( hps, &rectPage ) ;
383 
384             alOpt[0] = 0L ;
385             alOpt[1] = LT_ORIGINALVIEW ;
386             alOpt[2] = 0L ;
387             alOpt[3] = LC_LOADDISC ;
388             alOpt[4] = RES_DEFAULT ;
389             alOpt[5] = SUP_DEFAULT ;
390             alOpt[6] = CTAB_DEFAULT ;
391             alOpt[7] = CREA_DEFAULT ;
392             alOpt[8] = DDEF_DEFAULT ;
393             if (rc) rc=GpiPlayMetaFile( hps, hmf, 9L, alOpt, NULL, 255, buff ) ;
394 
395             if (rc) {
396               DevEscape( hdc, DEVESC_ENDDOC, 0L, NULL, NULL, NULL ) ;
397               msgRet = WM_USER_PRINT_OK ;
398               }
399             else
400               msgRet = WM_USER_PRINT_ERROR;
401 
402             }
403         else
404             msgRet = WM_USER_PRINT_ERROR ;
405 
406         GpiDestroyPS( hps ) ;
407         DevCloseDC( hdc ) ;
408         }
409     else
410         msgRet = WM_USER_DEV_ERROR ;
411 
412     DosEnterCritSec() ;
413     WinPostMsg( ptp->hwnd, msgRet, (MPARAM)WinGetLastError(hab), 0L ) ;
414     WinTerminate( hab ) ;
415     }
416 
OpenPrinterDC(HAB hab,PQPRINT pqp,LONG lMode,char * szPrintFile)417 HDC OpenPrinterDC( HAB hab, PQPRINT pqp, LONG lMode, char *szPrintFile )
418 /*
419 ** get printer info from os2.ini and set up DC
420 **
421 ** Input:  HAB hab  -- handle of anchor block of printing thread
422 **         PQPRINT-- pointer to data of current selected printer
423 **         LONG lMode -- mode in which device context is opened = OD_QUEUED, OD_DIRECT, OD_INFO
424 **         char *szPrintFile -- name of file for printer output, NULL
425 **                  if to printer (only used for devices that support file
426 **                  output eg plotter, postscript)
427 **
428 ** Return: HDC      -- handle of printer device context
429 **                   = DEV_ERROR (=0) if error
430 */
431     {
432     LONG   lType ;
433     static CHAR   achPrinterData[256] ;
434 
435     if( pqp->piPrinter == NULL ) return DEV_ERROR ;
436 
437     strcpy( achPrinterData, pqp->piPrinter->pszDriverName ) ;
438     achPrinterData[ strcspn(achPrinterData,".") ] = '\0' ;
439 
440     devop.pszDriverName = achPrinterData ;
441     devop.pszLogAddress = pqp->piPrinter->pszName ;
442 
443     if( pqp->pdriv != NULL
444         && strcmp( pqp->pdriv->szDeviceName, pqp->piPrinter->pDriverData->szDeviceName ) == 0 ) {
445         devop.pdriv = pqp->pdriv ;
446         }
447     else devop.pdriv = pqp->piPrinter->pDriverData ;
448 
449     if( szPrintFile != NULL )  devop.pszLogAddress = szPrintFile ;
450 
451             // set data type to RAW
452 
453     devop.pszDataType = "PM_Q_RAW" ;
454 
455             // open device context
456     if( lMode != 0L )
457         lType = lMode ;
458     else
459         lType = (szPrintFile == NULL) ? OD_QUEUED: OD_DIRECT ;
460 
461     return DevOpenDC( hab, //  WinQueryAnchorBlock( hwnd ),
462                       lType,
463                       "*",
464                       4L,
465                       (PDEVOPENDATA) &devop,
466                       NULLHANDLE ) ;
467     }
468 
FindPrinter(char * szName,PPRQINFO3 piPrinter)469 int FindPrinter( char *szName, PPRQINFO3 piPrinter )
470 /*
471 **  Find a valid printer
472 */
473     {
474     PPRQINFO3 pprq = NULL ;
475     PDRIVDATA pdriv = NULL ;
476     LONG np ;
477 
478     if( *szName && (strcmp( szName, piPrinter->pszName ) == 0) ) return 0 ;
479     if( GetPrinters( &pprq , &np ) == 0 ) return 1 ;
480     for( --np; np>=0; np-- ) {
481         if( strcmp( szName, pprq[np].pszName ) == 0 ) {
482             if( piPrinter->pDriverData != NULL ) free( piPrinter->pDriverData ) ;
483             pdriv = malloc( pprq[np].pDriverData->cb ) ;
484             memcpy( piPrinter, &pprq[np], sizeof( PRQINFO3 ) ) ;
485             piPrinter->pDriverData = pdriv ;
486             memcpy( pdriv, pprq[np].pDriverData, pprq[np].pDriverData->cb ) ;
487             free( pprq ) ;
488             return 0 ;
489             }
490         }
491     memcpy( piPrinter, &pprq[0], sizeof( PRQINFO3 ) ) ;
492     free( pprq ) ;
493     return 0 ;
494     }
495 
CancelPrintDlgProc(HWND hwnd,ULONG usMsg,MPARAM mp1,MPARAM mp2)496 MRESULT EXPENTRY CancelPrintDlgProc ( HWND hwnd, ULONG usMsg, MPARAM mp1, MPARAM mp2 )
497 /*
498 **  Cancel printing dialog box proc
499 */
500     {
501     switch ( usMsg ) {
502 
503         case WM_COMMAND :
504             switch ( SHORT1FROMMP(mp1) ) {
505                 case DID_CANCEL:
506                     WinSendMsg( WinQueryWindow( hwnd, QW_OWNER ),
507                                     WM_USER_PRINT_CANCEL,
508                                     0L,
509                                     0L ) ;
510                     WinDismissDlg( hwnd, 0 ) ;
511                     break ;
512                 default:
513                     break ;
514                 }
515         default:
516             break ;
517         }
518         /* fall through to the default control processing */
519     return WinDefDlgProc ( hwnd , usMsg , mp1 , mp2 ) ;
520     }
521 
522 
523