1 /*  Part of XPCE --- The SWI-Prolog GUI toolkit
2 
3     Author:        Jan Wielemaker and Anjo Anjewierden
4     E-mail:        jan@swi.psy.uva.nl
5     WWW:           http://www.swi.psy.uva.nl/projects/xpce/
6     Copyright (c)  1996-2013, University of Amsterdam
7     All rights reserved.
8 
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions
11     are met:
12 
13     1. Redistributions of source code must retain the above copyright
14        notice, this list of conditions and the following disclaimer.
15 
16     2. Redistributions in binary form must reproduce the above copyright
17        notice, this list of conditions and the following disclaimer in
18        the documentation and/or other materials provided with the
19        distribution.
20 
21     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25     COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32     POSSIBILITY OF SUCH DAMAGE.
33 */
34 
35 #include "include.h"
36 #include <h/unix.h>
37 
38 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
39 Taken from MSVC20/samples/win32/mfedit.h.
40 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
41 
42 #define META32_SIGNATURE        0x464D4520      // ' EMF'
43 #define ALDUS_ID		0x9AC6CDD7
44 
45 typedef struct
46 { DWORD		key;
47   WORD		hmf;
48   SMALL_RECT    bbox;
49   WORD    	inch;
50   DWORD   	reserved;
51   WORD    	checksum;
52 } APMFILEHEADER;
53 typedef APMFILEHEADER * PAPMFILEHEADER;
54 #define APMSIZE 22
55 
56 #ifndef MAXPATHLEN
57 #define MAXPATHLEN 1024
58 #endif
59 
60 Class ClassWinMF;			/* the class handle */
61 
62 NewClass(win_mf)			/* class structure */
63   ABSTRACT_GRAPHICAL
64   FileObj	file;			/* Associated file */
65   StringObj	summary;		/* Summary description */
66   HENHMETAFILE  hmf;			/* The metafile handle */
67 End;
68 
69 static status getDimensionsWinMF(WinMF mf);
70 static status getMhfWinMF(WinMF mf);
71 
72 static Chain WinMetaFiles;		/* @win_metafiles */
73 
74 static status
initialiseWinMF(WinMF mf,FileObj f)75 initialiseWinMF(WinMF mf, FileObj f)
76 { initialiseGraphical(mf, ZERO, ZERO, ZERO, ZERO);
77 
78   if ( isDefault(f) )
79     f = (FileObj) NIL;
80 
81   assign(mf, file, f);
82   mf->hmf = NULL;
83 
84   if ( notNil(f) )
85   { if ( !getDimensionsWinMF(mf) )
86       fail;
87   }
88 
89   return prependChain(WinMetaFiles, mf);
90 }
91 
92 
93 static status
closeWinMF(WinMF mf)94 closeWinMF(WinMF mf)
95 { if ( mf->hmf )
96   { DeleteEnhMetaFile(mf->hmf);
97 
98     mf->hmf = NULL;
99   }
100 
101   succeed;
102 }
103 
104 
105 static status
unlinkWinMF(WinMF mf)106 unlinkWinMF(WinMF mf)
107 { closeWinMF(mf);
108   deleteChain(WinMetaFiles, mf);
109 
110   return unlinkGraphical((Graphical) mf);
111 }
112 
113 
114 static void
closeAllWinMF(int rval)115 closeAllWinMF(int rval)
116 { if ( WinMetaFiles )
117   { Cell cell;
118 
119     for_cell(cell, WinMetaFiles)
120     { WinMF mf = cell->value;
121 
122       closeWinMF(mf);
123     }
124   }
125 }
126 
127 
128 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
129 Store/load windows metafile to/form file. Format:
130 
131 	* If the metafile has a file, just the slots and 'X'
132 	* Otherwise, the slots, 'E', <size>, metafilebitx
133 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
134 
135 static status
storeWinMF(WinMF mf,FileObj file)136 storeWinMF(WinMF mf, FileObj file)
137 { TRY(storeSlotsObject(mf, file));
138 
139   if ( isNil(mf->file) && mf->hmf )
140   { UINT size;
141 
142     if ( (size = GetEnhMetaFileBits(mf->hmf, 0, NULL)) )
143     { LPBYTE data = pceMalloc(size);
144       GetEnhMetaFileBits(mf->hmf, size, data);
145       Sputc('E', file->fd);
146       putstdw(size, file->fd);
147       Sfwrite(data, sizeof(char), size, file->fd);
148       pceFree(data);
149 
150       succeed;
151     }
152   }
153 
154   Sputc('X', file->fd);
155 
156   succeed;
157 }
158 
159 
160 static status
loadFdWinMF(WinMF mf,IOSTREAM * fd,ClassDef def)161 loadFdWinMF(WinMF mf, IOSTREAM *fd, ClassDef def)
162 { TRY( loadSlotsObject(mf, fd, def) );
163   mf->hmf = NULL;
164 
165   switch(Sgetc(fd))
166   { case 'X':
167       if ( notNil(mf->file) )
168 	getDimensionsWinMF(mf);
169       break;
170     case 'E':
171     { UINT size = loadWord(fd);
172       LPBYTE data = pceMalloc(size);
173       Sfread(data, sizeof(char), size, fd);
174       mf->hmf = SetEnhMetaFileBits(size, data);
175       pceFree(data);
176       break;
177     }
178     default:
179       assert(0);
180   }
181 
182   return prependChain(WinMetaFiles, mf);
183 }
184 
185 
186 static status
copyWinMF(WinMF to,WinMF from)187 copyWinMF(WinMF to, WinMF from)
188 { copyGraphical(to, from);
189 
190   assign(to, file, NIL);		/* ??? */
191   assign(to, summary, from->summary);
192 
193   if ( from->hmf )
194     to->hmf = CopyEnhMetaFile(from->hmf, NULL);
195   else
196     from->hmf = NULL;
197 
198   succeed;
199 }
200 
201 
202 static status
cloneWinMF(WinMF from,WinMF clone)203 cloneWinMF(WinMF from, WinMF clone)
204 { clonePceSlots(from, clone);
205   if ( from->hmf )
206     clone->hmf = CopyEnhMetaFile(from->hmf, NULL);
207 
208   succeed;
209 }
210 
211 
212 void
set_area_from_rectl(Area a,RECTL * r)213 set_area_from_rectl(Area a, RECTL *r)
214 { assign(a, x, toInt(r->left));
215   assign(a, y, toInt(r->top));
216   assign(a, w, toInt(1 + r->right - r->left));
217   assign(a, h, toInt(1 + r->bottom - r->top));
218 }
219 
220 
221 static status
getDimensionsWinMF(WinMF mf)222 getDimensionsWinMF(WinMF mf)
223 { UINT hdrsize;
224 
225   if ( !mf->hmf )
226   { if ( !getMhfWinMF(mf) )
227       fail;
228   }
229 
230   if ( (hdrsize = GetEnhMetaFileHeader(mf->hmf, 0, NULL)) )
231   { ENHMETAHEADER *hdr = alloca(hdrsize);
232 
233     GetEnhMetaFileHeader(mf->hmf, hdrsize, hdr);
234     set_area_from_rectl(mf->area, &hdr->rclBounds);
235     if ( hdr->nDescription )
236     { char *s = (char *)hdr + hdr->offDescription;
237       string str;
238 
239       str_set_n_ascii(&str, hdr->nDescription, s);
240       assign(mf, summary, StringToString(&str));
241     }
242 
243     succeed;
244   }
245 
246   fail;
247 }
248 
249 
250 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
251 Taken from MSVC20/samples/win32/mfedit.c and modified to fit into XPCE's
252 format.
253 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
254 
255 static HENHMETAFILE
hemfLoadMetafile(WinMF mf,const char * szFile)256 hemfLoadMetafile(WinMF mf, const char *szFile)
257 { HMETAFILE       ghmf, hmf;
258   UINT            uiSize;
259   LPVOID          pvData;
260   HDC             hDCDrawSurf;
261   HENHMETAFILE    hemf = NULL;
262 
263   HANDLE          hFile, hMapFile;
264   LPVOID          pMapFile;
265   LPENHMETAHEADER pemh;
266 
267   BOOL            bSuccess;
268 
269   bSuccess = TRUE;
270 
271   if ( (hFile=CreateFile(szFile,
272 			 GENERIC_READ, FILE_SHARE_READ, NULL,
273 			 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,
274 			 NULL)) == (HANDLE)-1 )
275   { errorPce(mf, NAME_winMetafile, NAME_open, APIError());
276     return 0L;
277   }
278 
279   /* Create a map file of the opened file */
280 
281   if ( (hMapFile=CreateFileMapping(hFile, NULL,
282 				   PAGE_READONLY, 0, 0, "MapF")) == NULL )
283   { errorPce(mf, NAME_winMetafile, NAME_map, APIError());
284     bSuccess = FALSE;
285     goto ErrorExit1;
286   }
287 
288   /* Map a view of the whole file */
289 
290   if ( (pMapFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0)) == NULL)
291   { errorPce(mf, NAME_winMetafile, NAME_view, APIError());
292     bSuccess = FALSE;
293     goto ErrorExit2;
294   }
295 
296   /* First check that if it is an enhanced metafile */
297 
298   pemh = (LPENHMETAHEADER) pMapFile;
299   if ( pemh->dSignature == META32_SIGNATURE )
300   { hemf = GetEnhMetaFile(szFile);
301     goto HLM_EXIT;
302   }
303 
304   /* If it has an ALDUS header skip it
305      Notice: APMSIZE is used because the HANDLE and RECT of the structure
306      depends on the environment
307   */
308   if ( *((LPDWORD)pemh) == ALDUS_ID )
309   { //METAFILEPICT    mfp;
310     PAPMFILEHEADER aldushdr = (PAPMFILEHEADER) pMapFile;
311 
312     DEBUG(NAME_winMetafile,
313 	  Cprintf("ALDUS Header: inch = %d, size = %d x %d\n",
314 		  aldushdr->inch,
315 		  aldushdr->bbox.Right,
316 		  aldushdr->bbox.Bottom));
317 
318     uiSize = *((LPDWORD) ((PBYTE)pMapFile + APMSIZE + 6));
319     hDCDrawSurf = GetDC(NULL);
320 
321     /* Notice: mtSize is size of the file in word.
322        if LPMETAFILEPICT is NULL
323        MM_ANISOTROPIC mode and default device size will be used.
324     */
325     hemf = SetWinMetaFileBits(uiSize*2L,
326 			      (PBYTE)pMapFile + APMSIZE, hDCDrawSurf, NULL);
327 #if 0
328     switch ( aldushdr->inch )
329     { /* !!! End up in an upside down image */
330       case 1440:
331 	mfp.mm = MM_TWIPS;
332         break;
333       case 2540:
334 	mfp.mm = MM_HIMETRIC;
335         break;
336       case 254:
337 	mfp.mm = MM_LOMETRIC;
338         break;
339       case 1000:
340 	mfp.mm = MM_HIENGLISH;
341         break;
342       case 100:
343 	mfp.mm = MM_LOENGLISH;
344         break;
345       default:
346 	mfp.mm = MM_ANISOTROPIC;
347         mfp.xExt = (((PAPMFILEHEADER) pMapFile)->bbox.Right -
348 		    ((PAPMFILEHEADER) pMapFile)->bbox.Left) *
349 			((PAPMFILEHEADER) pMapFile)->inch * 2560;
350 	mfp.yExt = (((PAPMFILEHEADER) pMapFile)->bbox.Bottom -
351 		    ((PAPMFILEHEADER) pMapFile)->bbox.Top) *
352 			((PAPMFILEHEADER) pMapFile)->inch * 2560;
353 	break;
354     }
355     mfp.hMF = 0;
356     hemf = SetWinMetaFileBits(uiSize*2L,
357 			      (PBYTE)pMapFile + APMSIZE, hDCDrawSurf, &mfp);
358 #endif
359 
360     if ( !hemf )
361     { errorPce(mf, NAME_winMetafile,
362 	       CtoName("SetWinMetaFileBits"), APIError());
363     }
364 
365     ghmf = SetMetaFileBitsEx(uiSize*2L, (PBYTE)pMapFile + APMSIZE);
366     if ( !ghmf )
367     { errorPce(mf, NAME_winMetafile,
368 	       CtoName("SetMetaFileBitsEx"), APIError());
369     }
370 
371     ReleaseDC(NULL, hDCDrawSurf);
372 
373     goto HLM_EXIT;
374   }
375 
376   /* It is a Windows 3x format metafile (hopefully) */
377 
378   if (!(hmf = GetMetaFile((LPCSTR)szFile)))
379   { errorPce(mf, NAME_winMetafile, CtoName("GetMetaFile"), APIError());
380     bSuccess = FALSE;
381     goto ErrorExit3;
382   }
383 
384   if ( !(uiSize = GetMetaFileBitsEx(hmf, 0, NULL)) )
385   { errorPce(mf, NAME_winMetafile, CtoName("GetMetaFileBitsEx-1"), APIError());
386     return NULL;
387   }
388 
389   if ((pvData = (LPVOID) LocalAlloc(LMEM_FIXED, uiSize)) == NULL)
390   { errorPce(mf, NAME_winMetafile, CtoName("alloc"), APIError());
391     bSuccess = FALSE;
392     goto ErrorExit3;
393   }
394 
395   if (!(uiSize = GetMetaFileBitsEx(hmf, uiSize, pvData)))
396   { errorPce(mf, NAME_winMetafile, CtoName("GetMetaFileBitsEx-2"), APIError());
397     bSuccess = FALSE;
398     goto ErrorExit3;
399   }
400 
401   DeleteMetaFile(hmf);
402 
403   hDCDrawSurf = GetDC(NULL);
404   hemf = SetWinMetaFileBits(uiSize, (LPBYTE)pvData, hDCDrawSurf, NULL);
405   ghmf = SetMetaFileBitsEx(uiSize, (LPBYTE) pvData);
406 
407   LocalFree(pvData);
408 
409   ReleaseDC(NULL, hDCDrawSurf);
410 
411 HLM_EXIT:
412 ErrorExit3:
413   UnmapViewOfFile(pMapFile);
414 
415 ErrorExit2:
416   CloseHandle(hMapFile);
417 ErrorExit1:
418   CloseHandle(hFile);
419 
420   if (bSuccess)
421     return hemf;
422   else
423     return 0L;
424 }
425 
426 
427 static status
getMhfWinMF(WinMF mf)428 getMhfWinMF(WinMF mf)
429 { if ( !mf->hmf && notNil(mf->file) )
430   { CharArray path = getClassVariableValueObject(mf, NAME_path);
431 
432     if ( findFile(mf->file, path ? path : (CharArray) DEFAULT, NAME_read) )
433     { char *rawfn = strName(getOsNameFile(mf->file));
434 
435 #if O_XOS
436       char fn[MAXPATHLEN];
437       if ( !_xos_os_filename(rawfn, fn, sizeof(fn)) )
438 	return errorPce(mf, NAME_representation, NAME_nameTooLong);
439 #else
440       char *fn = rawfn;
441 #endif
442 
443       if ( (mf->hmf = hemfLoadMetafile(mf, fn)) )
444 	succeed;
445     }
446   }
447 
448   fail;
449 }
450 
451 
452 static status
RedrawAreaWinMF(WinMF mf,Area a)453 RedrawAreaWinMF(WinMF mf, Area a)
454 { int x, y, w, h;
455 
456   initialiseDeviceGraphical(mf, &x, &y, &w, &h);
457 
458   if ( mf->hmf )
459     r_winmf(mf->hmf, x, y, w, h);
460 
461   return RedrawAreaGraphical(mf, a);
462 }
463 
464 		 /*******************************
465 		 *	  PAINTING IN IT	*
466 		 *******************************/
467 
468 static status
drawInWinMF(WinMF mf,Any obj,Point pos)469 drawInWinMF(WinMF mf, Any obj, Point pos)
470 { Int oldx, oldy;
471   Device dev;
472   wchar_t *fn;
473   wchar_t *descr;
474   Area bb;
475 
476   if ( notDefault(pos) && instanceOfObject(obj, ClassGraphical) )
477   { Graphical gr = obj;
478 
479     oldx = gr->area->x;
480     oldy = gr->area->y;
481     dev = gr->device;
482     gr->device = NIL;
483     setGraphical(gr, pos->x, pos->y, DEFAULT, DEFAULT);
484   } else
485   { oldx = oldy = DEFAULT;
486     dev = NIL;				/* keep compiler happy */
487   }
488 
489   if ( isNil(mf->file) )
490     fn = NULL;
491   else
492     fn = charArrayToWC((CharArray)getOsNameFile(mf->file), NULL);
493 
494   if ( isNil(mf->summary) )
495     descr = NULL;
496   else					/* application\0summary\0\0 */
497   { size_t slen;
498     wchar_t *summary, *s;
499     wchar_t *app = L"XPCE";
500 
501     summary = charArrayToWC((CharArray)mf->summary, &slen);
502     descr = alloca((slen + wcslen(app) + 3)*sizeof(wchar_t));
503     wcscpy(descr, summary);
504     s = descr + slen;
505     *s++ = L'\0';
506     wcscpy(s, app);
507     s += wcslen(app) + 1;
508     *s++ = L'\0';
509   }
510 
511   if ( instanceOfObject(obj, ClassGraphical) )
512   { Graphical gr = obj;
513 
514     ComputeGraphical(gr);
515     bb = gr->area;
516   } else /* if ( instanceOfObject(obj, ClassChain) ) */
517   { Cell cell;
518 
519     bb = answerObject(ClassArea, EAV);
520     for_cell(cell, (Chain)obj)
521     { Graphical gr = cell->value;
522 
523       if ( instanceOfObject(gr, ClassGraphical) )
524       { ComputeGraphical(gr);
525 	unionNormalisedArea(bb, gr->area);
526       }
527     }
528   }
529 
530 
531   CHANGING_GRAPHICAL(mf,
532     d_winmf(fn,
533 	    valInt(bb->x), valInt(bb->y), valInt(bb->w), valInt(bb->h),
534 	    descr);
535 
536     if ( instanceOfObject(obj, ClassGraphical) )
537     { Graphical gr = obj;
538 
539       RedrawArea(gr, gr->area);
540     } else
541     { Chain ch = obj;
542       Cell cell;
543 
544       for_cell(cell, ch)
545       { if ( instanceOfObject(cell->value, ClassGraphical) )
546 	{ Graphical gr = cell->value;
547 
548 	  RedrawArea(gr, gr->area);
549 	}
550       }
551     }
552 
553     mf->hmf = d_winmfdone();
554     copyArea(mf->area, bb);
555     doneObject(bb);
556     changedEntireImageGraphical(mf));
557 
558   if ( notDefault(oldx) )
559   { Graphical gr = obj;
560 
561     setGraphical(gr, oldx, oldy, DEFAULT, DEFAULT);
562     gr->device = dev;
563   }
564 
565   succeed;
566 }
567 
568 
569 static status
saveALDUS(WinMF mf,HMETAFILE ghmf,FileObj file,int width,int height,int mapping)570 saveALDUS(WinMF mf, HMETAFILE ghmf, FileObj file,
571 	  int width, int height, int mapping)
572 { UINT            uiSize;
573   int		  rval = TRUE;
574 
575   uiSize = GetMetaFileBitsEx(ghmf, 0, NULL);
576 
577   if ( !send(file, NAME_kind, NAME_binary, EAV) ||
578        !send(file, NAME_open, NAME_write, EAV) )
579     fail;
580 
581   if ( uiSize )
582   { APMFILEHEADER   AldHdr;
583     WORD	   *p;
584     void *	    buf;
585 
586     AldHdr.key = ALDUS_ID;
587     AldHdr.hmf = 0;                                 // Unused; must be zero
588     AldHdr.bbox.Left   = 0;                         // in metafile units
589     AldHdr.bbox.Top    = 0;
590 
591     switch (mapping)
592     { case MM_HIENGLISH:
593 	AldHdr.inch = 1000;
594         AldHdr.bbox.Right  = (SHORT)width;
595 	AldHdr.bbox.Bottom = (SHORT)height;
596 	break;
597       case MM_HIMETRIC:
598 	AldHdr.inch = 1440;
599         AldHdr.bbox.Right  = (SHORT)(width / 2540 * 1440);
600 	AldHdr.bbox.Bottom = (SHORT)(height / 2540 * 1440);
601 	break;
602       case MM_LOENGLISH:
603 	AldHdr.inch = 100;
604         AldHdr.bbox.Right  = (SHORT)width;
605 	AldHdr.bbox.Bottom = (SHORT)height;
606 	break;
607       case MM_LOMETRIC:
608 	AldHdr.inch = 254;
609         AldHdr.bbox.Right  = (SHORT)width;
610 	AldHdr.bbox.Bottom = (SHORT)height;
611 	break;
612       case MM_TEXT:
613       { HDC hdc = GetDC(NULL);
614 
615 	AldHdr.inch = (WORD) ((float)GetDeviceCaps(hdc, HORZRES) * 25.4 /
616 			      (float)GetDeviceCaps(hdc, HORZSIZE));
617         AldHdr.bbox.Right  = (SHORT)width;
618 	AldHdr.bbox.Bottom = (SHORT)height;
619 
620 	DEBUG(NAME_winMetafile,
621 	      Cprintf("HORZRES = %d, HORZSIZE = %d, inch = %d right = %d\n",
622 		      GetDeviceCaps(hdc, HORZRES),
623 		      GetDeviceCaps(hdc, HORZSIZE),
624 		      AldHdr.inch,
625 		      AldHdr.bbox.Right));
626 
627 	ReleaseDC(NULL, hdc);
628 	break;
629       }
630       case MM_TWIPS:
631 	AldHdr.inch = 1440;
632         AldHdr.bbox.Right  = (SHORT)width;
633 	AldHdr.bbox.Bottom = (SHORT)height;
634 	break;
635       default:
636 	AldHdr.inch = 1440;
637         AldHdr.bbox.Right  = (SHORT)((width  * 1440) / 2540);
638 	AldHdr.bbox.Bottom = (SHORT)((height * 1440) / 2540);
639 	break;
640     }
641 
642 
643     AldHdr.reserved = 0;
644     AldHdr.checksum = 0;
645     for (p = (WORD *)&AldHdr; p < (WORD *)&(AldHdr.checksum); ++p)
646       AldHdr.checksum ^= *p;
647 
648     if ( Sfwrite(&AldHdr, APMSIZE, 1, file->fd) != 1 )
649     { reportErrorFile(file);
650       closeFile(file);
651       fail;
652     }
653 
654     buf = pceMalloc(uiSize);
655     GetMetaFileBitsEx(ghmf, uiSize, buf);
656     if ( Sfwrite(buf, sizeof(char), uiSize, file->fd) != uiSize )
657     { reportErrorFile(file);
658       closeFile(file);
659       pceFree(buf);
660 
661       fail;
662     }
663     pceFree(buf);
664 
665     return closeFile(file);
666   }
667 
668   return rval;
669 }
670 
671 
672 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
673 Get a Windows 3.x format metafile  from   the  XPCE object. I'm not sure
674 whether the allocated  memory  block  should   be  freed  or  not.  Some
675 analogous cases in  mfedit  indicate   me  SetMetaFileBitsEx()  probably
676 copies the data, so the code below should be fine.
677 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
678 
679 static HMETAFILE
convert_enh_metafile(WinMF mf,HDC hdc)680 convert_enh_metafile(WinMF mf, HDC hdc)
681 { void *data = NULL;
682   int len, l2;
683   int fnMapMode = MM_ANISOTROPIC;
684   int omap = SetMapMode(hdc, fnMapMode);
685   HMETAFILE hmf;
686 					/* get old format bits */
687 
688   if ( !(len = GetWinMetaFileBits(mf->hmf, 0, NULL, fnMapMode, hdc)) )
689   { errorPce(mf, NAME_winMetafile,
690 	     CtoName("GetWinMetaFileBits"), APIError());
691     return NULL;
692   }
693 
694   data = pceMalloc(len);
695   l2 = GetWinMetaFileBits(mf->hmf, len, data, fnMapMode, hdc);
696   SetMapMode(hdc, omap);
697   assert(l2 == len);
698 					/* make old format metafile */
699   hmf = SetMetaFileBitsEx(l2, data);
700   pceFree(data);
701 
702   return hmf;
703 }
704 
705 
706 
707 static status
saveWinMF(WinMF mf,FileObj file,Name format)708 saveWinMF(WinMF mf, FileObj file, Name format)
709 { char *rawfn = strName(getOsNameFile(file));
710 #if O_XOS
711   char fn[MAXPATHLEN];
712   if ( !_xos_os_filename(rawfn, fn, sizeof(fn)) )
713     return errorPce(mf, NAME_representation, NAME_nameTooLong);
714 #else
715   char *fn = rawfn;
716 #endif
717 
718   if ( !mf->hmf )
719     fail;
720 
721 
722   if ( isDefault(format) )
723   { if ( suffixCharArray((CharArray)file->name,
724 			 (CharArray)CtoName(".wmf"),
725 			 ON) )
726       format = NAME_aldus;
727     else if ( suffixCharArray((CharArray)file->name,
728 			      (CharArray)CtoName(".emf"),
729 			      ON) )
730       format = NAME_emf;
731     else
732       format = getClassVariableValueObject(mf, NAME_format);
733   }
734 
735   if ( format == NAME_wmf || format == NAME_aldus )
736   { HDC hdc = GetDC(NULL);
737     HMETAFILE ohmf = convert_enh_metafile(mf, hdc);
738     HMETAFILE ohmf2 = NULL;
739     status rval = SUCCEED;
740 
741     ReleaseDC(NULL, hdc);
742 
743     if ( format == NAME_wmf )
744     { if ( !(ohmf2 = CopyMetaFile(ohmf, fn)) )
745       { DeleteMetaFile(ohmf);
746 	return errorPce(mf, NAME_winMetafile,
747 			CtoName("CopyMetaFile"), APIError());
748       }
749     } else /* ALDUS */
750       rval = saveALDUS(mf, ohmf, file,
751 		       valInt(mf->area->w), valInt(mf->area->h),
752 		       MM_TEXT);
753 
754     DeleteMetaFile(ohmf2);
755     DeleteMetaFile(ohmf);
756 
757     return rval;
758   } else				/* save as enhanced format */
759   { HENHMETAFILE h2;
760 
761     if ( (h2 = CopyEnhMetaFile(mf->hmf, fn)) )
762     { DeleteEnhMetaFile(h2);
763       succeed;
764     } else
765       return errorPce(mf, NAME_winMetafile,
766 		      CtoName("CopyEnhMetaFile"), APIError());
767   }
768 }
769 
770 		 /*******************************
771 		 *	 WINDOWS CUT/PASTE	*
772 		 *******************************/
773 
774 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
775 Copy a metafile to the windows clipboard.  I'm not really sure about the
776 immediate delete, but that is what mfedit is doing. Also, shouldn't this
777 use GlobalAlloc() somehow??
778 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
779 
780 status
ws_on_clipboard_metafile(WinMF mf,Name type)781 ws_on_clipboard_metafile(WinMF mf, Name type)
782 { if ( mf->hmf )
783   { if ( type == NAME_emf )
784     { HENHMETAFILE hmftmp = CopyEnhMetaFile(mf->hmf, NULL);
785 
786       if ( hmftmp )
787       { SetClipboardData(CF_ENHMETAFILE, hmftmp);
788 	DeleteEnhMetaFile(hmftmp);
789 
790 	succeed;
791       }
792     } else /* if ( type == NAME_wmf ) */
793     { HGLOBAL hmem;
794       LPMETAFILEPICT  lpmfp;
795       HDC hdc  = GetDC(NULL);
796       int hmm  = GetDeviceCaps(hdc, HORZSIZE);
797       int hpxl = GetDeviceCaps(hdc, HORZRES);
798       int vmm  = GetDeviceCaps(hdc, VERTSIZE);
799       int vpxl = GetDeviceCaps(hdc, VERTRES);
800 
801       if ( !(hmem = GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,
802 				sizeof(METAFILEPICT))) )
803       { errorPce(mf, NAME_winMetafile, CtoName("GlobalAlloc"), APIError());
804 	fail;
805       }
806 
807       lpmfp = (LPMETAFILEPICT)GlobalLock(hmem);
808       lpmfp->mm = MM_ANISOTROPIC;
809 
810       lpmfp->xExt = (valInt(mf->area->w)*hmm*100)/hpxl;
811       lpmfp->yExt = (valInt(mf->area->h)*vmm*100)/vpxl;
812       lpmfp->hMF  = convert_enh_metafile(mf, hdc); /* Reclaim??? */
813 
814       GlobalUnlock(hmem);
815       SetClipboardData(CF_METAFILEPICT, hmem);
816 
817       ReleaseDC(NULL, hdc);
818     }
819   }
820 
821   fail;
822 }
823 
824 
825 WinMF
CtoWinMetafile(HENHMETAFILE hmf)826 CtoWinMetafile(HENHMETAFILE hmf)
827 { WinMF mf = answerObject(ClassWinMF, EAV);
828 
829   mf->hmf = hmf;
830   getDimensionsWinMF(mf);
831 
832   answer(mf);
833 }
834 
835 
836 		 /*******************************
837 		 *	 CLASS DECLARATION	*
838 		 *******************************/
839 
840 /* Type declarations */
841 
842 static char *T_drawIn[] =
843         { "graphical|chain", "at=[point]" };
844 static char *T_save[] =
845 	{ "in=file", "format=[{aldus,wmf,emf}]" };
846 
847 /* Instance Variables */
848 
849 static vardecl var_winmf[] =
850 { IV(NAME_file, "file*", IV_GET,
851      NAME_storage, "Associated physical file"),
852   IV(NAME_summary, "string*", IV_BOTH,
853      NAME_manual, "Description associated with the file"), /* TBD:group */
854   IV(NAME_handle, "alien:HENHMETAFILE", IV_NONE,
855      NAME_storage, "Handle to the Win32 metafile"),
856 };
857 
858 /* Send Methods */
859 
860 static senddecl send_winmf[] =
861 { SM(NAME_initialise, 1, "[file]*", initialiseWinMF,
862      DEFAULT, "Create box from width and height"),
863   SM(NAME_unlink, 0, NULL, unlinkWinMF,
864      DEFAULT, "Remove from @win_metafiles"),
865   SM(NAME_drawIn, 2, T_drawIn, drawInWinMF,
866      NAME_copy, "Paint graphical in metafile"),
867   SM(NAME_copy, 1, "win_metafile", copyWinMF,
868      NAME_copy, "Copy the argument to the receiver"),
869   SM(NAME_save, 2, T_save, saveWinMF,
870      NAME_file, "Save contents in specified file"),
871 };
872 
873 /* Get Methods */
874 
875 #define get_winmf NULL
876 /*
877 static getdecl get_winmf[] =
878 {
879 };
880 */
881 
882 /* Resources */
883 
884 static classvardecl rc_winmf[] =
885 { RC(NAME_path, "string",
886      "\".:mf:~/lib/mf:$PCEHOME/mf:\"",
887      "Search path for loading Windows metafiles"),
888   RC(NAME_format, "{emf,wmf,aldus}",
889      "aldus",
890      "Default save format")
891 };
892 
893 /* Class Declaration */
894 
895 static Name winmf_termnames[] = { NAME_file };
896 
897 ClassDecl(winmf_decls,
898           var_winmf, send_winmf, get_winmf, rc_winmf,
899           1, winmf_termnames,
900           "$Rev$");
901 
902 
903 status
makeClassWinMF(Class class)904 makeClassWinMF(Class class)
905 { declareClass(class, &winmf_decls);
906 
907   setRedrawFunctionClass(class, RedrawAreaWinMF);
908   WinMetaFiles = globalObject(NAME_winMetafiles, ClassChain, EAV);
909   setLoadStoreFunctionClass(class, loadFdWinMF, storeWinMF);
910   setCloneFunctionClass(class, cloneWinMF);
911 
912   at_pce_exit(closeAllWinMF, ATEXIT_FIFO);
913 
914   succeed;
915 }
916