/* Copyright (C) 1994 artofcode LLC. All rights reserved. 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. */ /*$Id: gspmdrv.c,v 1.2.6.1.2.1 2003/01/17 00:49:03 giles Exp $ */ /* Presentation Manager driver for Ghostscript */ /* Written by Russell Lang */ /* To display output from os2pm driver: */ /* gspmdrv -d id_string */ /* To display BMP file (used for testing display code) */ /* gspmdrv -b filename.bmp */ #define INCL_DOS #define INCL_WIN #define INCL_GPI #include #include #include #include #include #include "gspmdrv.h" #include "gdevpm.h" #ifndef min #define min(x,y) ( (x) < (y) ? (x) : (y) ) #endif #ifndef max #define max(x,y) ( (x) > (y) ? (x) : (y) ) #endif HEV update_event_sem; HMTX bmp_mutex_sem; /* bitmap details */ typedef struct tagBM { BOOL valid; BOOL old_bmp; /* bitmap type */ PBITMAPINFO2 pbmi; /* pointer to bitmap info */ PBYTE bits; /* pointer to bitmap bits */ int width; int height; int planes; int depth; int palsize; int palimportant; int old_width; int old_height; int old_planes; int old_depth; int old_palsize; int old_palimportant; } BMAP; typedef struct tagDISPLAY { LONG planes; LONG bitcount; LONG hasPalMan; /* Palette Manager */ BOOL hpal_exists; HPAL hpal; } DISPLAY; /* options that are saved in INI file */ typedef struct tagOPTIONS { POINTL img_origin; POINTL img_size; BOOL img_max; } OPTIONS; #define CW_USEDEFAULT 32768 BMAP bitmap; DISPLAY display; OPTIONS option; PBYTE bbuffer; /* for BMP file display */ POINTL scroll_pos; /* not used *//* not used */ ULONG os_version; char *section = "Ghostscript Image"; HAB hab; /* Anchor Block */ HWND hwnd_frame; HWND hwnd_bmp; HWND hwnd_gs; /* window handle for CMD.EXE that started gs */ TID update_tid; #define WM_GSUPDATE WM_USER+1 #define SB_TOP 20 #define SB_BOTTOM 21 MRESULT EXPENTRY ClientWndProc(HWND, ULONG, MPARAM, MPARAM); MRESULT EXPENTRY AboutDlgProc(HWND, ULONG, MPARAM, MPARAM); APIRET init_window(void); void fix_sysmenu(HWND); APIRET restore_window_position(SWP * pswp); BOOL scan_bitmap(BMAP * pbm); void read_profile(void); void write_profile(void); APIRET init_display(int argc, char *argv[]); APIRET init_bitmap(int argc, char *argv[]); void copy_clipboard(void); HBITMAP make_bitmap(BMAP * pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth); void debugbeep(int type) { #ifdef DEBUG int i; /* current debug beeps are: */ /* 1. Null handle PS */ /* 2. make_bitmap() failed */ /* 3. GpiDrawBits() or WinDrawBitmap() failed */ /* 4. Null handle PS from WinBeginPaint() */ for (i = 0; i < type; i++) { DosBeep(400 + 100 * type, 50); DosSleep(50); } #endif } /* display message */ int message_box(char *str, int icon) { return WinMessageBox(HWND_DESKTOP, hwnd_frame ? hwnd_frame : HWND_DESKTOP, str, "gspmdrv.exe", 0, icon | MB_MOVEABLE | MB_OK); } void error_message(char *str) { WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "gspmdrv.exe", 0, MB_MOVEABLE | MB_ICONHAND | MB_OK); WinPostMsg(hwnd_frame, WM_QUIT, MPFROMLONG(0), MPFROMLONG(0)); } /* Update thread */ /* This thread waits for the update event semaphore from gs.exe */ /* then generates a WM_PAINT message for the bitmap */ /* This thread must NOT call C library functions */ VOID APIENTRY update_func(ULONG unused) { APIRET rc; BOOL flag; ULONG count; unused = unused; /* to shut up warning */ while (!DosQueryEventSem(update_event_sem, &count)) { /* loop while semaphore exists */ DosWaitEventSem(update_event_sem, SEM_INDEFINITE_WAIT); DosResetEventSem(update_event_sem, &count); WinPostMsg(hwnd_bmp, WM_GSUPDATE, MPFROMLONG(0), MPFROMLONG(0)); } } VOID APIENTRY exit_func(ULONG code) { write_profile(); DosCloseEventSem(update_event_sem); DosCloseMutexSem(bmp_mutex_sem); DosFreeMem((PVOID) bitmap.pbmi); DosExitList(EXLST_EXIT, 0); code = code; /* to shut up warning */ } void find_hwnd_gs(char *gsid) { ULONG ulCount; ULONG ulLength; ULONG pBase; ULONG cbBuf; PSWBLOCK pswblk; PSWENTRY pswentry; SWCNTRL *pswc; int i; ULONG pid; char buf[256]; char *p, *s; PTIB pptib; PPIB pppib; /* extract gs pid from command line id */ strcpy(buf, gsid); for (p = buf; *p && *p != '_'; p++); *p++ = '\0'; s = p; for (p = buf; *p && *p != '_'; p++); *p = '\0'; pid = atoi(s); /* pid is Process ID of CMD.EXE that started gsos2.exe */ ulCount = WinQuerySwitchList(hab, NULL, 0); /* get num of items */ cbBuf = (ulCount * sizeof(SWENTRY)) + sizeof(HSWITCH); pswblk = (PSWBLOCK) malloc(cbBuf + 32768); ulCount = WinQuerySwitchList(hab, pswblk, cbBuf); /* get num of items */ for (i = 0; i < ulCount; i++) { pswentry = &pswblk->aswentry[i]; pswc = &pswentry->swctl; if (pid == pswc->idProcess) hwnd_gs = pswc->hwnd; /* save window handle */ } } int main(int argc, char *argv[]) { HMQ hand_mq; /* message queue */ QMSG q_mess; /* message queue */ APIRET rc = 0; hab = WinInitialize(0); /* Get the Anchor Block */ hand_mq = WinCreateMsgQueue(hab, 0); /* start a queue */ if (argc < 2) { rc = 1; error_message("Usage: gspmdrv -d id_string"); } if (!rc) { if (strcmp(argv[1], "-d") == 0) { rc = init_display(argc, argv); } else if (strcmp(argv[1], "-b") == 0) { rc = init_bitmap(argc, argv); } else { rc = 1; error_message("Usage: gspmdrv -d id_string"); } } if (!rc) { rc = DosCreateThread(&update_tid, update_func, 0, 0, 8192); if (rc) error_message("Failed to create update thread"); } if (!rc) rc = init_window(); if (!rc) WinShowWindow(hwnd_frame, TRUE); if (!rc) { /* keep gspmdrv.exe in memory for number of minutes specified in */ /* environment variable GS_LOAD */ _emxload_env("GS_LOAD"); } DosExitList(EXLST_ADD, exit_func); /* message loop */ while (!rc && WinGetMsg(hab, &q_mess, 0L, 0, 0)) WinDispatchMsg(hab, &q_mess); /* Shut down the application window and queue */ DosKillThread(update_tid); WinDestroyWindow(hwnd_frame); WinDestroyMsgQueue(hand_mq); WinTerminate(hab); return rc; } APIRET init_window() { ULONG version[3]; SWP swp; APIRET rc = 0; ULONG flFlags; /* Window frame definition */ unsigned char class[] = "gspmdrvClass"; /* class name */ if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION, &version, sizeof(version))) os_version = 201000; /* a guess */ else { os_version = version[0] * 10000 + version[1] * 100 + version[2]; } /* define the frame constants */ flFlags = FCF_TITLEBAR | /* have a title bar */ FCF_SIZEBORDER | /* have a sizeable window */ FCF_MINMAX | /* have a min and max button */ FCF_SYSMENU | /* include a system menu */ FCF_VERTSCROLL | /* vertical scroll bar */ FCF_HORZSCROLL | /* horizontal scroll bar */ FCF_TASKLIST | /* show it in window list */ FCF_ICON; /* Load icon from resources */ /* save SHELL default size and location */ rc = WinQueryTaskSizePos(hab, 0, &swp); if (rc) return rc; read_profile(); if ((option.img_size.x == 0) || (option.img_size.y == 0)) option.img_size.x = option.img_size.y = CW_USEDEFAULT; if (!rc) { HPS ps = WinGetPS(HWND_DESKTOP); HDC hdc = GpiQueryDevice(ps); DevQueryCaps(hdc, CAPS_COLOR_PLANES, 1, &display.planes); DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &display.bitcount); DevQueryCaps(hdc, CAPS_ADDITIONAL_GRAPHICS, 1, &display.hasPalMan); display.hasPalMan &= CAPS_PALETTE_MANAGER; WinReleasePS(ps); } if (!rc) { if (!WinRegisterClass( /* register this window class */ hab, /* anchor block */ (PSZ) class, /* class name */ (PFNWP) ClientWndProc, /* window function */ CS_SIZEREDRAW | /* window style */ CS_MOVENOTIFY, 0)) /* no storage */ exit(1); hwnd_frame = WinCreateStdWindow( HWND_DESKTOP, /* window type */ 0, /* frame style is not WS_VISIBLE */ &flFlags, /* definitions */ (PSZ) class, /* client class */ (PSZ) "Ghostscript Image", /* title */ WS_VISIBLE, /* client style */ 0, /* resource module */ ID_GSPMDRV, /* resource identifier */ &hwnd_bmp); /* pointer to client */ fix_sysmenu(hwnd_frame); } rc = restore_window_position(&swp); return rc; } void write_profile(void) { char profile[64]; sprintf(profile, "%d %d", option.img_origin.x, option.img_origin.y); PrfWriteProfileString(HINI_USERPROFILE, section, "Origin", profile); sprintf(profile, "%d %d", option.img_size.x, option.img_size.y); PrfWriteProfileString(HINI_USERPROFILE, section, "Size", profile); sprintf(profile, "%d", option.img_max); PrfWriteProfileString(HINI_USERPROFILE, section, "Maximized", profile); } void read_profile(void) { char profile[64]; PrfQueryProfileString(HINI_USERPROFILE, section, "Origin", "", profile, sizeof(profile)); if (sscanf(profile, "%d %d", &option.img_origin.x, &option.img_origin.y) != 2) { option.img_origin.x = CW_USEDEFAULT; option.img_origin.y = CW_USEDEFAULT; } PrfQueryProfileString(HINI_USERPROFILE, section, "Size", "", profile, sizeof(profile)); if (sscanf(profile, "%d %d", &option.img_size.x, &option.img_size.y) != 2) { option.img_size.x = CW_USEDEFAULT; option.img_size.y = CW_USEDEFAULT; } PrfQueryProfileString(HINI_USERPROFILE, section, "Maximized", "", profile, sizeof(profile)); if (sscanf(profile, "%d", &option.img_max) != 1) option.img_max = 0; } void fix_sysmenu(HWND hwnd) { MENUITEM mi; HWND hwndSysMenu; if (!WinSendMsg(WinWindowFromID(hwnd, FID_SYSMENU), MM_QUERYITEM, MPFROM2SHORT(SC_SYSMENU, TRUE), MPFROMP(&mi))) { message_box("failed getting system menu handle", 0); return; } hwndSysMenu = mi.hwndSubMenu; mi.iPosition = MIT_END; mi.afStyle = MIS_SEPARATOR; mi.afAttribute = 0; mi.id = 0; mi.hwndSubMenu = 0; mi.hItem = 0; WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), NULL); mi.afStyle = MIS_TEXT; mi.id = IDM_ABOUT; WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "About..."); mi.id = IDM_COPY; WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "Copy"); } APIRET restore_window_position(SWP * pswp) { SWP swp; swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW; if (option.img_max) { /* Get maximized frame window position and size. */ if (!WinGetMaxPosition(hwnd_frame, &swp)) return 1; swp.fl |= SWP_MAXIMIZE; } else if ((option.img_size.x != CW_USEDEFAULT) && (option.img_size.y != CW_USEDEFAULT) && (option.img_origin.y != CW_USEDEFAULT) && (option.img_origin.y != CW_USEDEFAULT)) { LONG cxClientMax; LONG cyClientMax; LONG cyTitleBar; LONG cxSizeBorder; LONG cySizeBorder; /* get maximum client window size */ cxClientMax = WinQuerySysValue(HWND_DESKTOP, SV_CXFULLSCREEN); cyClientMax = WinQuerySysValue(HWND_DESKTOP, SV_CYFULLSCREEN); cyTitleBar = WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR); cxSizeBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER); cySizeBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER); cyClientMax += cyTitleBar; /* Make sure x origin is within display boundaries */ swp.x = option.img_origin.x; if (swp.x < -cxSizeBorder) swp.x = 0; /* Make sure window isn't too wide, or negative value */ swp.cx = option.img_size.x; if (swp.cx >= cxClientMax || swp.cx < 0) { swp.cx = cxClientMax; swp.x = 0; } if ((swp.x + swp.cx) > (cxClientMax + cxSizeBorder)) swp.x = cxClientMax + cxSizeBorder - swp.cx; /* Make sure y origin is within display boundaries */ swp.y = option.img_origin.y; if (swp.y < -cySizeBorder) swp.y = 0; /* Make sure window isn't too high, or negative value */ swp.cy = option.img_size.y; if (swp.cy > cyClientMax || swp.cy < 0) { swp.cy = cyClientMax; swp.y = 0; } if ((swp.y + swp.cy) > (cyClientMax + cySizeBorder)) swp.y = cyClientMax + cySizeBorder - swp.cy; } else { /* No saved position -- use supplied position */ swp = *pswp; option.img_origin.x = swp.x; option.img_origin.y = swp.y; option.img_size.x = swp.cx; option.img_size.y = swp.cy; option.img_max = FALSE; swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW; } if (hwnd_gs) swp.fl |= SWP_ZORDER; /* Position and size this frame window */ if (!WinSetWindowPos(hwnd_frame, hwnd_gs, swp.x, swp.y, swp.cx, swp.cy, swp.fl)) return 1; return 0; } APIRET init_display(int argc, char *argv[]) { char buf[256]; char name[256]; APIRET rc = 0; if (argc != 3) { rc = 1; error_message("Usage: gspmdrv -d id_string"); } find_hwnd_gs(argv[2]); if (!rc) { sprintf(name, SHARED_NAME, argv[2]); rc = DosGetNamedSharedMem((PVOID *) & bitmap.pbmi, name, PAG_READ | PAG_WRITE); if (rc) { sprintf(buf, "Failed to open: bmp shared memory \"%s\" rc = %d", argv[0], rc); error_message(buf); } } if (!rc) { sprintf(name, SYNC_NAME, argv[2]); rc = DosOpenEventSem(name, &update_event_sem); if (rc) { sprintf(buf, "Failed to open: update event semaphore \"%s\" rc = %d", argv[1], rc); error_message(buf); } } if (!rc) { sprintf(name, MUTEX_NAME, argv[2]); rc = DosOpenMutexSem(name, &bmp_mutex_sem); if (rc) { sprintf(buf, "Failed to open: bmp mutex semaphore \"%s\" rc = %d", argv[1], rc); error_message(buf); } } if (!rc) { scan_bitmap(&bitmap); bitmap.valid = TRUE; } return rc; } APIRET init_bitmap(int argc, char *argv[]) { char buf[256]; APIRET rc = 0; HFILE hf; ULONG action, count, length; PBITMAPFILEHEADER2 pbmfh; if (argc != 3) return 1; /* error - no filename */ /* open bitmap */ if ((rc = DosOpen(argv[2], &hf, &action, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE, 0)) != (APIRET) 0) { sprintf(buf, "Error opening: %s", argv[2]); error_message(buf); return rc; } rc = DosSetFilePtr(hf, 0, FILE_END, &length); if (rc) { sprintf(buf, "failed seeking to EOF: error = %d", rc); error_message(buf); return rc; } rc = DosSetFilePtr(hf, 0, FILE_BEGIN, &count); if (rc) { sprintf(buf, "failed seeking to BOF: error = %d", rc); error_message(buf); return rc; }; /* allocate memory for bitmap */ if ((rc = DosAllocMem((PPVOID) & bbuffer, length, PAG_READ | PAG_WRITE | PAG_COMMIT)) != (APIRET) 0) { sprintf(buf, "failed allocating memory"); error_message(buf); return rc; } rc = DosRead(hf, bbuffer, length, &count); DosClose(hf); if (rc) { sprintf(buf, "failed reading bitmap, error = %u, count = %u", rc, count); error_message(buf); return rc; } /* extract some info about bitmap */ pbmfh = (PBITMAPFILEHEADER2) bbuffer; bitmap.pbmi = (PBITMAPINFO2) (&pbmfh->bmp2); scan_bitmap(&bitmap); bitmap.valid = TRUE; sprintf(buf, "bitmap width = %d, height = %d", bitmap.width, bitmap.height); message_box(buf, 0); return rc; } #define MAX_PAL_SIZE 256 void make_palette(BMAP * pbm) { ULONG tbl[MAX_PAL_SIZE]; PRGB2 palptr = (PRGB2) ((PBYTE) (pbm->pbmi) + pbm->pbmi->cbFix); RGB *old_palptr = (RGB *) palptr; int palcount = pbm->palimportant; int i; BOOL old_bmp = (pbm->pbmi->cbFix == sizeof(BITMAPINFOHEADER)); if (old_bmp) { for (i = 0; i < palcount; i++) { tbl[i] = (old_palptr->bRed << 16) + (old_palptr->bGreen << 8) + (old_palptr->bBlue); palptr++; } } else { for (i = 0; i < palcount; i++) { tbl[i] = (palptr->bRed << 16) + (palptr->bGreen << 8) + (palptr->bBlue); palptr++; } } if (display.hpal_exists) GpiDeletePalette(display.hpal); display.hpal = GpiCreatePalette(hab, 0L, LCOLF_CONSECRGB, palcount, tbl); display.hpal_exists = TRUE; } /* scan bitmap */ /* update bitmap structure */ /* return value is TRUE if bitmap dimension has changed */ BOOL scan_bitmap(BMAP * pbm) { PBITMAPINFO2 pbmi = pbm->pbmi; PBITMAPINFO old_pbmi = (PBITMAPINFO) pbmi; BOOL old_bmp = (pbmi->cbFix == sizeof(BITMAPINFOHEADER)); if (old_bmp) { /* it is a BITMAPINFO */ switch (old_pbmi->cBitCount) { case 24: pbm->palsize = 0; break; case 8: pbm->palsize = 256; break; case 4: pbm->palsize = 16; break; case 1: pbm->palsize = 2; break; default: pbm->valid = FALSE; error_message("scan_bitmap: wrong number of bits"); /* panic */ return FALSE; } pbm->palimportant = pbm->palsize; pbm->palsize = pbm->palsize * sizeof(RGB); pbm->bits = (PBYTE) old_pbmi + old_pbmi->cbFix + pbm->palsize; pbm->width = old_pbmi->cx; pbm->height = old_pbmi->cy; pbm->planes = old_pbmi->cPlanes; pbm->depth = old_pbmi->cBitCount; } else { /* it is a BITMAPINFO2 */ switch (pbmi->cBitCount) { case 24: pbm->palsize = 0; break; case 8: pbm->palsize = 256; break; case 4: pbm->palsize = 16; break; case 1: pbm->palsize = 2; break; default: pbm->valid = FALSE; error_message("scan_bitmap: wrong number of bits"); /* panic */ return FALSE; } if ((pbmi->cbFix > (&(pbmi->cclrUsed) - &(pbmi->cbFix))) && (pbmi->cclrUsed != 0) && (pbmi->cBitCount != 24)) pbm->palsize = pbmi->cclrUsed; pbm->palimportant = pbm->palsize; if ((pbmi->cbFix > (&(pbmi->cclrImportant) - &(pbmi->cbFix))) && (pbmi->cclrImportant != 0) && (pbmi->cBitCount != 24)) pbm->palimportant = pbmi->cclrImportant; pbm->palsize = pbm->palsize * sizeof(RGB2); pbm->bits = (PBYTE) pbmi + pbmi->cbFix + pbm->palsize; pbm->width = pbmi->cx; pbm->height = pbmi->cy; pbm->planes = pbmi->cPlanes; pbm->depth = pbmi->cBitCount; } if ((pbm->palsize != pbm->old_palsize) || (pbm->palimportant != pbm->old_palimportant)) { if ((pbm->depth == 8) && display.hasPalMan) make_palette(pbm); pbm->old_palimportant = pbm->palimportant; } if ((pbm->width == pbm->old_width) && (pbm->height == pbm->old_height) && (pbm->planes == pbm->old_planes) && (pbm->depth == pbm->old_depth) && (pbm->palsize == pbm->old_palsize) && (pbm->old_bmp == old_bmp)) return FALSE; /* bitmap has changed */ pbm->old_width = pbm->width; pbm->old_height = pbm->height; pbm->old_planes = pbm->planes; pbm->old_depth = pbm->depth; pbm->old_palsize = pbm->palsize; pbm->old_bmp = old_bmp; return TRUE; } void update_scroll_bars(void) { /* Cause update of scroll bars etc. */ SWP swp; WinQueryWindowPos(hwnd_bmp, &swp); WinSendMsg(hwnd_bmp, WM_SIZE, MPFROM2SHORT(swp.cx, swp.cy), MPFROM2SHORT(swp.cx, swp.cy)); } /* copy bitmap to the clipboard */ void copy_clipboard(void) { HBITMAP hbmp; if (!bitmap.valid) { message_box("Cannot copy to clipboard:\nNo Bitmap displayed", 0); return; } if (WinOpenClipbrd(hab)) { /* get bmp mutex to stop gs.exe changing bitmap while we copy it */ DosRequestMutexSem(bmp_mutex_sem, 10000); if (scan_bitmap(&bitmap)) { /* bitmap has changed */ update_scroll_bars(); } hbmp = make_bitmap(&bitmap, 0, 0, bitmap.width, bitmap.height, bitmap.depth); if (hbmp) { WinEmptyClipbrd(hab); WinSetClipbrdData(hab, (ULONG) hbmp, CF_BITMAP, CFI_HANDLE); } DosReleaseMutexSem(bmp_mutex_sem); WinCloseClipbrd(hab); } } HBITMAP make_bitmap(BMAP * pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth) { HDC hdc = DEV_ERROR, hdcMem = DEV_ERROR; HPS hps = GPI_ERROR; HBITMAP hbmp = GPI_ERROR, hbmr = HBM_ERROR; SIZEL sizePS; BITMAPINFOHEADER2 bmih; if ((left == right) || (bottom == top)) return (HBITMAP) NULL; if (right > pbm->width) right = pbm->width; if (left > pbm->width) left = 0; if (top > pbm->height) top = pbm->height; if (bottom > pbm->height) bottom = 0; memset(&bmih, 0, sizeof(bmih)); bmih.cbFix = sizeof(BITMAPINFOHEADER2); bmih.cx = right - left; bmih.cy = top - bottom; bmih.cPlanes = 1; bmih.cBitCount = depth; /* create memory DC compatible with screen */ hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 0L, NULL, NULLHANDLE); sizePS.cx = right - left; sizePS.cy = top - bottom; if (hdcMem != DEV_ERROR) hps = GpiCreatePS(hab, hdcMem, &sizePS, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC); if (hps != GPI_ERROR) hbmp = GpiCreateBitmap(hps, &bmih, 0L, NULL, NULL); if (hbmp != GPI_ERROR) hbmr = GpiSetBitmap(hps, hbmp); if (hbmr != HBM_ERROR) { LONG rc; ERRORID eid; POINTL apts[4]; /* target is inclusive */ apts[0].x = 0; apts[0].y = 0; apts[1].x = right - left - 1; apts[1].y = top - bottom - 1; /* source is not inclusive of top & right borders */ apts[2].x = left; apts[2].y = bottom; apts[3].x = right; apts[3].y = top; rc = 0; eid = WinGetLastError(hab); rc = GpiDrawBits(hps, pbm->bits, pbm->pbmi, 4, apts, (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0); if (rc == 0) { char buf[256]; eid = WinGetLastError(hab); sprintf(buf, "make_bitmap: GpiDrawBits rc = %08x, eid = %08x", rc, eid); message_box(buf, 0); } } if (hbmr != HBM_ERROR) GpiSetBitmap(hps, (ULONG) 0); if (hps != GPI_ERROR) GpiDestroyPS(hps); if (hdcMem != DEV_ERROR) DevCloseDC(hdcMem); if ((hbmr == HBM_ERROR) || (hdcMem == DEV_ERROR) || (hbmp == GPI_ERROR) || (hps == GPI_ERROR)) { if (hbmp != GPI_ERROR) GpiDeleteBitmap(hbmp); debugbeep(2); return 0; } return hbmp; } MRESULT paint_bitmap(HPS ps, PRECTL prect, int scrollx, int scrolly) { POINTL apts[4]; int wx, wy; if (WinIsRectEmpty(hab, prect)) return 0; if (ps == NULLHANDLE) { debugbeep(1); } /* source is not inclusive of top & right borders */ wx = prect->xRight - prect->xLeft; /* update width */ wy = prect->yTop - prect->yBottom; /* update height */ apts[2].x = prect->xLeft + scrollx; apts[2].y = prect->yBottom + scrolly; if (apts[2].x > bitmap.width) apts[2].x = bitmap.width; if (apts[2].x + wx > bitmap.width) wx = bitmap.width - apts[2].x; apts[3].x = apts[2].x + wx; if (apts[2].y > bitmap.height) apts[2].y = bitmap.height; if (apts[2].y + wy > bitmap.height) wy = bitmap.height - apts[2].y; apts[3].y = apts[2].y + wy; /* target is inclusive */ apts[0].x = prect->xLeft; apts[0].y = prect->yBottom; apts[1].x = prect->xLeft + wx - 1; apts[1].y = prect->yBottom + wy - 1; if ((display.bitcount == 4) /* standard VGA is buggy */ ||((os_version == 201100) && (display.bitcount == 8) && (bitmap.depth == 1)) /* S3 and ATI GU are buggy */ ) { /* slow code to dodge OS/2 bugs */ /* this code double buffers the bitmap and works on a standard VGA * but didn't work on an ATI Ultra Graphics Pro in 8514 emulation */ /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 8bit/pixel bitmap */ HBITMAP hbmp; /* create a bitmap */ hbmp = make_bitmap(&bitmap, apts[2].x, apts[2].y, apts[3].x, apts[3].y, bitmap.depth); /* Draw it to the display */ if (hbmp) { WinDrawBitmap(ps, hbmp, NULL, &apts[0], CLR_BLACK, CLR_WHITE, DBM_NORMAL); GpiDeleteBitmap(hbmp); } } else { /* fast code which doesn't always work */ /* This code works on the Trident SVGA and 8514 in 256 color mode, * but GpiDrawBits fails with a SYS3175 on the standard VGA. */ /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 1bit/pixel bitmap */ GpiDrawBits(ps, bitmap.bits, bitmap.pbmi, 4, apts, (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0); } return 0; } /* This is the window function */ MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG mess, MPARAM mp1, MPARAM mp2) { char buf[256]; static int cxClient, cyClient; static int cxAdjust, cyAdjust; static int nHscrollMax, nHscrollPos; static int nVscrollMax, nVscrollPos; int nHscrollInc; int nVscrollInc; HWND hwndScroll; HPS hps; RECTL rect; ULONG ulclr; switch (mess) { case WM_CREATE: break; case WM_ERASEBACKGROUND: /* by returning TRUE, the Presentation Manager automatically clears * the window each time the window is resized or moved. */ return (MRESULT) TRUE; case WM_GSUPDATE: if (!WinInvalidateRect(hwnd_bmp, (PRECTL) NULL, TRUE)) error_message("error invalidating rect"); if (!WinUpdateWindow(hwnd_bmp)) error_message("error updating window"); return 0; case WM_COMMAND: switch (LONGFROMMP(mp1)) { case IDM_ABOUT: WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, 0, IDD_ABOUT, 0); break; case IDM_COPY: copy_clipboard(); break; } break; case WM_REALIZEPALETTE: if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) { hps = WinGetPS(hwnd); if (hps == NULLHANDLE) debugbeep(1); GpiSelectPalette(hps, display.hpal); if (WinRealizePalette(hwnd, hps, &ulclr) > 0) WinInvalidateRect(hwnd, NULL, FALSE); GpiSelectPalette(hps, (HPAL) NULL); WinReleasePS(hps); return 0; } break; /* use default processing */ case WM_PAINT: /* Refresh the window each time the WM_PAINT message is received */ /* get bmp mutex to stop gs.exe changing bitmap while we paint */ DosRequestMutexSem(bmp_mutex_sem, 10000); if (scan_bitmap(&bitmap)) update_scroll_bars(); /* bitmap has changed */ if (!bitmap.valid) { DosReleaseMutexSem(bmp_mutex_sem); hps = WinBeginPaint(hwnd, (ULONG) 0, &rect); if (hps == NULLHANDLE) debugbeep(4); WinFillRect(hps, &rect, CLR_BACKGROUND); WinEndPaint(hwnd); return 0; } hps = WinBeginPaint(hwnd, (HPS) NULL, &rect); if (hps == NULLHANDLE) debugbeep(4); if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) { GpiSelectPalette(hps, display.hpal); WinRealizePalette(hwnd, hps, &ulclr); paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos); GpiSelectPalette(hps, (HPAL) NULL); } else paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos); WinEndPaint(hwnd); DosReleaseMutexSem(bmp_mutex_sem); return 0; case WM_MOVE: /* don't interrogate the window location immediately since */ /* it causes the Diamond Stealth VL24 with IBM S3 drivers */ /* to corrupt the display */ DosSleep(50); if (hwnd_frame) { /* save window position for INI file */ SWP swp; WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp); if (!(swp.fl & SWP_MINIMIZE)) { option.img_origin.x = swp.x; option.img_origin.y = swp.y; option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0); } } return 0; case WM_SIZE: cyClient = SHORT2FROMMP(mp2); cxClient = SHORT1FROMMP(mp2); cyAdjust = min(bitmap.height, cyClient) - cyClient; cyClient += cyAdjust; nVscrollMax = max(0, bitmap.height - cyClient); nVscrollPos = min(nVscrollPos, nVscrollMax); scroll_pos.y = nVscrollMax - nVscrollPos; if (!bitmap.valid) cyClient = cyAdjust = nVscrollMax = nVscrollPos; hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL); WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nVscrollPos), MPFROM2SHORT(0, nVscrollMax)); if (bitmap.valid) WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cyClient, bitmap.height), MPFROMLONG(0)); else WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1), MPFROMLONG(0)); cxAdjust = min(bitmap.width, cxClient) - cxClient; cxClient += cxAdjust; nHscrollMax = max(0, bitmap.width - cxClient); nHscrollPos = min(nHscrollPos, nHscrollMax); scroll_pos.x = nHscrollPos; if (!bitmap.valid) cxClient = cxAdjust = nHscrollMax = nHscrollPos; hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL); WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nHscrollPos), MPFROM2SHORT(0, nHscrollMax)); if (bitmap.valid) WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cxClient, bitmap.width), MPFROMLONG(0)); else WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1), MPFROMLONG(0)); if ((cxAdjust != 0 || cyAdjust != 0)) { SWP swp; WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp); WinSetWindowPos(WinQueryWindow(hwnd, QW_PARENT), 0, swp.x, swp.y - cyAdjust, swp.cx + cxAdjust, swp.cy + cyAdjust, SWP_SIZE | SWP_MOVE); cxAdjust = cyAdjust = 0; } if (hwnd_frame) { /* save window size for INI file */ SWP swp; WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp); if (!(swp.fl & SWP_MINIMIZE)) { option.img_size.x = swp.cx; option.img_size.y = swp.cy; option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0); } } break; case WM_VSCROLL: switch (SHORT2FROMMP(mp2)) { case SB_LINEUP: nVscrollInc = -cyClient / 16; break; case SB_LINEDOWN: nVscrollInc = cyClient / 16; break; case SB_PAGEUP: nVscrollInc = min(-1, -cyClient); break; case SB_PAGEDOWN: nVscrollInc = max(1, cyClient); break; case SB_SLIDERPOSITION: nVscrollInc = SHORT1FROMMP(mp2) - nVscrollPos; break; case SB_TOP: nVscrollInc = -nVscrollPos; break; case SB_BOTTOM: nVscrollInc = nVscrollMax - nVscrollPos; break; default: nVscrollInc = 0; } if ((nVscrollInc = max(-nVscrollPos, min(nVscrollInc, nVscrollMax - nVscrollPos))) != 0) { LONG lComplexity; hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL); nVscrollPos += nVscrollInc; scroll_pos.y = nVscrollMax - nVscrollPos; lComplexity = WinScrollWindow(hwnd, 0, nVscrollInc, (PRECTL) NULL, (PRECTL) NULL, (HRGN) NULLHANDLE, (PRECTL) & rect, 0); WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nVscrollPos), 0); if (lComplexity != RGN_RECT) { WinInvalidateRect(hwnd, (PRECTL) NULL, FALSE); WinUpdateWindow(hwnd); } else { /* redraw exposed area */ hps = WinGetPS(hwnd); if (hps == NULLHANDLE) debugbeep(1); if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) { GpiSelectPalette(hps, display.hpal); WinRealizePalette(hwnd, hps, &ulclr); paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos); GpiSelectPalette(hps, (HPAL) NULL); } else paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos); WinReleasePS(hps); } } break; case WM_HSCROLL: switch (SHORT2FROMMP(mp2)) { case SB_LINELEFT: nHscrollInc = -cxClient / 16; break; case SB_LINERIGHT: nHscrollInc = cyClient / 16; break; case SB_PAGELEFT: nHscrollInc = min(-1, -cxClient); break; case SB_PAGERIGHT: nHscrollInc = max(1, cxClient); break; case SB_SLIDERPOSITION: nHscrollInc = SHORT1FROMMP(mp2) - nHscrollPos; break; default: nHscrollInc = 0; } if ((nHscrollInc = max(-nHscrollPos, min(nHscrollInc, nHscrollMax - nHscrollPos))) != 0) { LONG lComplexity; hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL); nHscrollPos += nHscrollInc; scroll_pos.x = nHscrollPos; lComplexity = WinScrollWindow(hwnd, -nHscrollInc, 0, (PRECTL) NULL, (PRECTL) NULL, (HRGN) NULLHANDLE, (PRECTL) & rect, 0); /* need to send next message BEFORE redrawing, otherwise S3 driver screws up */ WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nHscrollPos), 0); if (lComplexity != RGN_RECT) { WinInvalidateRect(hwnd, (PRECTL) NULL, FALSE); WinUpdateWindow(hwnd); } else { /* redraw exposed area */ hps = WinGetPS(hwnd); if (hps == NULLHANDLE) debugbeep(1); if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) { GpiSelectPalette(hps, display.hpal); WinRealizePalette(hwnd, hps, &ulclr); paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos); GpiSelectPalette(hps, (HPAL) NULL); } else paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos); WinReleasePS(hps); } } break; case WM_CHAR: /* process keystrokes here */ if (SHORT1FROMMP(mp1) & KC_CHAR) { /* pass control to gs if ENTER pressed */ if (hwnd_gs && (SHORT1FROMMP(mp2) == '\r')) WinSetActiveWindow(HWND_DESKTOP, hwnd_gs); } /* Process only key presses, not key releases */ if (SHORT1FROMMP(mp1) & KC_KEYUP) break; if (SHORT1FROMMP(mp1) & KC_VIRTUALKEY) { USHORT vkey = SHORT2FROMMP(mp2); switch (vkey) { case VK_HOME: WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_TOP)); break; case VK_END: WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_BOTTOM)); break; case VK_UP: WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEUP)); break; case VK_DOWN: WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEDOWN)); break; case VK_PAGEUP: WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEUP)); break; case VK_PAGEDOWN: WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEDOWN)); break; case VK_LEFT: if (SHORT1FROMMP(mp1) & KC_CTRL) WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGELEFT)); else WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINELEFT)); break; case VK_RIGHT: if (SHORT1FROMMP(mp1) & KC_CTRL) WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGERIGHT)); else WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINERIGHT)); break; } } break; default: /* All messages not handled by the ClientWndProc must be passed * along to the Presentation Manager for default processing */ return WinDefWindowProc(hwnd, mess, mp1, mp2); } return (MRESULT) FALSE; } /* About Dialog Box */ MRESULT EXPENTRY AboutDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { switch (msg) { case WM_COMMAND: switch (COMMANDMSG(&msg)->cmd) { case DID_OK: WinDismissDlg(hwnd, TRUE); return (MRESULT) TRUE; } break; } return WinDefDlgProc(hwnd, msg, mp1, mp2); }