tuxpaint-pencil-sharpener/src/win32_print.c
John Popplewell a85bc639be WIN32 only:
Change use_print_config (printcfg) default to be yes.
Create the 'lockfile.dat' in the users local temporary directory, usually:
'C:\Documents and Settings\<USER NAME>\Local Settings\Temp\'. This allows
the use of a shared 'savedir' without messing up the lockfile.
2007-04-28 02:52:11 +00:00

604 lines
14 KiB
C

/* win32_print.c */
/* printing support for Tux Paint */
/* John Popplewell <john@johnnypops.demon.co.uk> */
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Sept. 30, 2002 - Oct. 17, 2002 */
/* Oct. 07, 2003 - added banding support */
/* - prints using 24-bit (not 32-bit) bitmap */
/* $Id$ */
#include <windows.h>
#include <direct.h>
#include "SDL_syswm.h"
#include "win32_print.h"
#include "debug.h"
#define NOREF(x) ((x)=(x))
#define GETHINST(hWnd) ((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE))
#define MIR(id) (MAKEINTRESOURCE(id))
static PRINTDLG global_pd = {
sizeof(PRINTDLG),
NULL, NULL, NULL, NULL,
PD_RETURNDC,
0xFFFF,
0xFFFF,
0xFFFF,
0xFFFF,
1,
0, 0, 0, 0, 0, 0, 0, 0,
};
static SDL_Surface *make24bitDIB(SDL_Surface * surf)
{
SDL_PixelFormat pixfmt;
SDL_Surface *surf24;
SDL_Surface *surfDIB;
Uint8 *src, *dst;
Uint32 linesize;
int i;
memset(&pixfmt, 0, sizeof(pixfmt));
pixfmt.palette = NULL;
pixfmt.BitsPerPixel = 24;
pixfmt.BytesPerPixel = 3;
pixfmt.Rmask = 0x00FF0000;
pixfmt.Gmask = 0x0000FF00;
pixfmt.Bmask = 0x000000FF;
pixfmt.Amask = 0;
pixfmt.Rshift = 16;
pixfmt.Gshift = 8;
pixfmt.Bshift = 0;
pixfmt.Ashift = 0;
pixfmt.Rloss = 0;
pixfmt.Gloss = 0;
pixfmt.Bloss = 0;
pixfmt.Aloss = 0;
pixfmt.colorkey = 0;
pixfmt.alpha = 0;
surf24 = SDL_ConvertSurface(surf, &pixfmt, SDL_SWSURFACE);
surfDIB = SDL_CreateRGBSurface(SDL_SWSURFACE, surf24->w, surf24->h, 24,
pixfmt.Rmask, pixfmt.Gmask, pixfmt.Bmask,
pixfmt.Amask);
linesize = surf24->w * 3; // Flip top2bottom
dst = surfDIB->pixels;
src = ((Uint8 *) surf24->pixels) + ((surf24->h - 1) * surf24->pitch);
for (i = 0; i < surf24->h; ++i)
{
memcpy(dst, src, linesize);
src -= surf24->pitch;
dst += surfDIB->pitch;
}
SDL_FreeSurface(surf24); // Free temp surface
return surfDIB;
}
/* returns 0 if failed */
static int GetDefaultPrinterStrings(char *device, char *driver, char *output)
{
const char *section = "windows";
const char *key = "device";
const char *def = "NODEFAULTPRINTER";
char buff[MAX_PATH];
char *dev, *drv, *out;
if (!GetProfileString(section, key, def, buff, sizeof(buff)))
return 0;
if (strcmp(buff, def) == 0)
return 0;
if (((dev = strtok(buff, ",")) != NULL) &&
((drv = strtok(NULL, ", ")) != NULL) &&
((out = strtok(NULL, ", ")) != NULL))
{
if (device)
strcpy(device, dev);
if (driver)
strcpy(driver, drv);
if (output)
strcpy(output, out);
return 1;
}
return 0;
}
#define dmDeviceNameSize 32
static HANDLE LoadCustomPrinterHDEVMODE(HWND hWnd, const char *filepath)
{
char device[MAX_PATH];
HANDLE hPrinter = NULL;
int sizeof_devmode;
HGLOBAL hDevMode = NULL;
DEVMODE *devmode = NULL;
int res;
FILE *fp = NULL;
int block_size;
int block_read;
if ((fp = fopen(filepath, "rb")) == NULL)
return NULL;
if (fread(device, 1, dmDeviceNameSize, fp) != dmDeviceNameSize)
goto err_exit;
if (!OpenPrinter(device, &hPrinter, NULL))
return NULL;
sizeof_devmode = (int) DocumentProperties(hWnd, hPrinter, device,
NULL, NULL, 0);
if (!sizeof_devmode)
goto err_exit;
hDevMode = GlobalAlloc(GHND, sizeof_devmode);
if (!hDevMode)
goto err_exit;
devmode = (DEVMODE *) GlobalLock(hDevMode);
if (!devmode)
goto err_exit;
res = DocumentProperties(hWnd, hPrinter, device, devmode, NULL,
DM_OUT_BUFFER);
if (res != IDOK)
goto err_exit;
block_size = devmode->dmSize + devmode->dmDriverExtra;
block_read = fread(devmode, 1, block_size, fp);
if (block_size != block_read)
goto err_exit;
fclose(fp);
res = DocumentProperties(hWnd, hPrinter, device, devmode, devmode,
DM_IN_BUFFER | DM_OUT_BUFFER);
if (res != IDOK)
goto err_exit;
GlobalUnlock(hDevMode);
ClosePrinter(hPrinter);
return hDevMode;
err_exit:
if (fp)
fclose(fp);
if (devmode)
GlobalUnlock(hDevMode);
if (hDevMode)
GlobalFree(hDevMode);
if (hPrinter)
ClosePrinter(hPrinter);
return NULL;
}
static int SaveCustomPrinterHDEVMODE(HWND hWnd, const char *filepath,
HANDLE hDevMode)
{
FILE *fp = NULL;
NOREF(hWnd);
if ((fp = fopen(filepath, "wb")) != NULL)
{
DEVMODE *devmode = (DEVMODE *) GlobalLock(hDevMode);
int block_size = devmode->dmSize + devmode->dmDriverExtra;
int block_written;
char devname[dmDeviceNameSize];
strcpy(devname, (const char *) devmode->dmDeviceName);
fwrite(devname, 1, sizeof(devname), fp);
block_written = fwrite(devmode, 1, block_size, fp);
GlobalUnlock(hDevMode);
fclose(fp);
return block_size == block_written;
}
return 0;
}
static HDC GetCustomPrinterDC(HWND hWnd, const char *printcfg, int show)
{
global_pd.hwndOwner = hWnd;
global_pd.hDC = NULL;
global_pd.hDevNames = NULL;
if (global_pd.hDevMode == NULL)
{
global_pd.hDevMode = LoadCustomPrinterHDEVMODE(hWnd, printcfg);
}
if (show)
{
if (PrintDlg(&global_pd))
{
SaveCustomPrinterHDEVMODE(hWnd, printcfg, global_pd.hDevMode);
return global_pd.hDC;
}
return NULL;
}
{
DEVMODE *devmode = (DEVMODE *) GlobalLock(global_pd.hDevMode);
global_pd.hDC =
CreateDC(NULL, (const char *) devmode->dmDeviceName, NULL, devmode);
GlobalUnlock(global_pd.hDevMode);
}
return global_pd.hDC;
}
static HDC GetDefaultPrinterDC(void)
{
char device[MAX_PATH], driver[MAX_PATH], output[MAX_PATH];
if (GetDefaultPrinterStrings(device, driver, output))
return CreateDC(driver, device, output, NULL);
return NULL;
}
static HDC GetPrinterDC(HWND hWnd, const char *printcfg, int show)
{
if (!printcfg)
return GetDefaultPrinterDC();
return GetCustomPrinterDC(hWnd, printcfg, show);
}
static int IsBandingRequired(HDC hPrinter)
{
OSVERSIONINFO osvi;
int indata = NEXTBAND;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&osvi) && (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT))
return Escape(hPrinter, QUERYESCSUPPORT, sizeof(int), (LPCSTR) & indata,
NULL);
return 0;
}
int IsPrinterAvailable(void)
{
return (GetDefaultPrinterStrings(NULL, NULL, NULL) != 0);
}
const char *SurfacePrint(SDL_Surface * surf, const char *printcfg,
int showdialog)
{
const char *res = NULL;
HWND hWnd;
DOCINFO di;
int nError;
SDL_SysWMinfo wminfo;
HDC hDCwindow;
HDC hDCprinter;
BITMAPINFOHEADER bmih;
SDL_Surface *surf24 = NULL;
RECT rc;
float fLogPelsX1, fLogPelsY1, fLogPelsX2, fLogPelsY2;
float fScaleX, fScaleY;
int cWidthPels, xLeft, yTop;
float subscaler, subscalerx, subscalery;
int hDCCaps;
HBITMAP hbm = NULL;
HDC hdcMem = NULL;
SDL_VERSION(&wminfo.version);
if (!SDL_GetWMInfo(&wminfo))
return "win32_print: SDL_GetWMInfo() failed.";
hWnd = wminfo.window;
hDCprinter = GetPrinterDC(hWnd, printcfg, showdialog);
if (!hDCprinter)
return "win32_print: GetPrinterDC() failed.";
EnableWindow(hWnd, FALSE);
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "Tux Paint";
di.lpszOutput = (LPTSTR) NULL;
di.lpszDatatype = (LPTSTR) NULL;
di.fwType = 0;
nError = StartDoc(hDCprinter, &di);
if (nError == SP_ERROR)
{
res = "win32_print: StartDoc() failed.";
goto error;
}
nError = StartPage(hDCprinter);
if (nError <= 0)
{
res = "win32_print: StartPage() failed.";
goto error;
}
//////////////////////////////////////////////////////////////////////////////////////
surf24 = make24bitDIB(surf);
if (!surf24)
{
res = "win32_print: make24bitDIB() failed.";
goto error;
}
memset(&bmih, 0, sizeof(bmih));
bmih.biSize = sizeof(bmih);
bmih.biPlanes = 1;
bmih.biCompression = BI_RGB;
bmih.biBitCount = 24;
bmih.biWidth = surf24->w;
bmih.biHeight = surf24->h;
GetClientRect(hWnd, &rc);
subscalerx = (float) rc.right / surf24->w;
subscalery = (float) rc.bottom / surf24->h;
subscaler = subscalery;
if (subscalerx < subscalery)
subscaler = subscalerx;
hDCwindow = GetDC(hWnd);
if (!hDCwindow)
{
res = "win32_print: failed to get window DC.";
goto error;
}
fLogPelsX1 = GetDeviceCaps(hDCwindow, LOGPIXELSX);
fLogPelsY1 = GetDeviceCaps(hDCwindow, LOGPIXELSY);
ReleaseDC(hWnd, hDCwindow);
fLogPelsX2 = GetDeviceCaps(hDCprinter, LOGPIXELSX);
fLogPelsY2 = GetDeviceCaps(hDCprinter, LOGPIXELSY);
if (fLogPelsX1 > fLogPelsX2)
fScaleX = (fLogPelsX1 / fLogPelsX2);
else
fScaleX = (fLogPelsX2 / fLogPelsX1);
if (fLogPelsY1 > fLogPelsY2)
fScaleY = (fLogPelsY1 / fLogPelsY2);
else
fScaleY = (fLogPelsY2 / fLogPelsY1);
fScaleX *= subscaler;
fScaleY *= subscaler;
yTop = 0;
cWidthPels = GetDeviceCaps(hDCprinter, PHYSICALWIDTH);
xLeft = ((cWidthPels - ((int) (fScaleX * bmih.biWidth))) / 2) -
GetDeviceCaps(hDCprinter, PHYSICALOFFSETX);
hDCCaps = GetDeviceCaps(hDCprinter, RASTERCAPS);
if (hDCCaps & RC_PALETTE)
{
res = "win32_print: printer context requires palette.";
goto error;
}
if (IsBandingRequired(hDCprinter))
{
RECT rcBand = { 0, 0, 0, 0 };
RECT rcPrinter;
RECT rcImage;
SetRect(&rcPrinter, xLeft, yTop, (int) (fScaleX * bmih.biWidth),
(int) (fScaleY * bmih.biHeight));
SetRect(&rcImage, 0, 0, bmih.biWidth, bmih.biHeight);
while (Escape(hDCprinter, NEXTBAND, 0, NULL, &rcBand))
{
if (IsRectEmpty(&rcBand))
break;
if (IntersectRect(&rcBand, &rcBand, &rcPrinter))
{
rcImage.top = (int) (0.5f + (float) rcBand.top / fScaleX);
rcImage.bottom = (int) (0.5f + (float) rcBand.bottom / fScaleX);
SetStretchBltMode(hDCprinter, COLORONCOLOR);
nError = StretchDIBits(hDCprinter, rcBand.left, rcBand.top,
rcBand.right - rcBand.left,
rcBand.bottom - rcBand.top,
rcImage.left, rcImage.top,
rcImage.right - rcImage.left,
rcImage.bottom - rcImage.top,
surf24->pixels, (BITMAPINFO *) & bmih,
DIB_RGB_COLORS, SRCCOPY);
if (nError == GDI_ERROR)
{
res = "win32_print: StretchDIBits() failed.";
goto error;
}
}
}
}
else
{
if (hDCCaps & RC_STRETCHDIB)
{
SetStretchBltMode(hDCprinter, COLORONCOLOR);
nError = StretchDIBits(hDCprinter, xLeft, yTop,
(int) (fScaleX * bmih.biWidth),
(int) (fScaleY * bmih.biHeight),
0, 0, bmih.biWidth, bmih.biHeight,
surf24->pixels, (BITMAPINFO *) & bmih,
DIB_RGB_COLORS, SRCCOPY);
if (nError == GDI_ERROR)
{
res = "win32_print: StretchDIBits() failed.";
goto error;
}
}
else
{
res = "win32_print: StretchDIBits() not available.";
goto error;
}
}
//////////////////////////////////////////////////////////////////////////////////////
nError = EndPage(hDCprinter);
if (nError <= 0)
{
res = "win32_print: EndPage() failed.";
goto error;
}
EndDoc(hDCprinter);
error:
if (hdcMem)
DeleteDC(hdcMem);
if (hbm)
DeleteObject(hbm);
if (surf24)
SDL_FreeSurface(surf24);
EnableWindow(hWnd, TRUE);
DeleteDC(hDCprinter);
return res;
}
/*
Read access to Windows Registry
*/
static HRESULT ReadRegistry(const char *key, const char *option, char *value,
int size)
{
LONG res;
HKEY hKey = NULL;
res = RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey);
if (res != ERROR_SUCCESS)
goto err_exit;
res =
RegQueryValueEx(hKey, option, NULL, NULL, (LPBYTE) value,
(LPDWORD) & size);
if (res != ERROR_SUCCESS)
goto err_exit;
res = ERROR_SUCCESS;
err_exit:
if (hKey)
RegCloseKey(hKey);
return HRESULT_FROM_WIN32(res);
}
/*
Removes a single '\' or '/' from end of path
*/
static char *remove_slash(char *path)
{
int len = strlen(path);
if (!len)
return path;
if (path[len - 1] == '/' || path[len - 1] == '\\')
path[len - 1] = 0;
return path;
}
/*
Returns heap string containing default application data path.
Creates suffix subdirectory (only one level).
E.g. C:\Documents and Settings\jfp\Application Data\suffix
*/
char *GetDefaultSaveDir(const char *suffix)
{
char prefix[MAX_PATH];
char path[2 * MAX_PATH];
const char *key =
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
const char *option = "AppData";
HRESULT hr = S_OK;
if (SUCCEEDED(hr = ReadRegistry(key, option, prefix, sizeof(prefix))))
{
remove_slash(prefix);
snprintf(path, sizeof(path), "%s/%s", prefix, suffix);
_mkdir(path);
return strdup(path);
}
return strdup("userdata");
}
/*
Returns heap string containing system font directory.
E.g. 'C:\Windows\Fonts'
*/
char *GetSystemFontDir(void)
{
char path[MAX_PATH];
const char *key =
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
const char *option = "Fonts";
HRESULT hr = S_OK;
if (SUCCEEDED(hr = ReadRegistry(key, option, path, sizeof(path))))
{
remove_slash(path);
return strdup(path);
}
return strdup("C:\\WINDOWS\\FONTS");
}
/*
Returns heap string containing user temp directory.
E.g. C:\Documents and Settings\jfp\Local Settings\Temp
*/
static char *GetUserTempDir(void)
{
char *temp = getenv("TEMP");
if (!temp)
{
temp = "userdata";
}
return strdup(temp);
}
char *get_temp_fname(const char *const name)
{
char f[512];
char *tempdir = GetUserTempDir();
snprintf(f, sizeof(f), "%s/%s", tempdir, name);
free(tempdir);
return strdup(f);
}