xref: /plan9/sys/src/cmd/gs/src/gspmdrv.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1994 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gspmdrv.c,v 1.4 2002/02/21 22:24:52 giles Exp $ */
18 /* Presentation Manager driver for Ghostscript */
19 /* Written by Russell Lang */
20 
21 /* To display output from os2pm driver: */
22 /*   gspmdrv -d id_string */
23 /* To display BMP file (used for testing display code) */
24 /*   gspmdrv -b filename.bmp */
25 
26 #define INCL_DOS
27 #define INCL_WIN
28 #define INCL_GPI
29 #include <os2.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/emxload.h>
34 #include "gspmdrv.h"
35 #include "gdevpm.h"
36 
37 #ifndef min
38 #define min(x,y)  ( (x) < (y) ? (x) : (y) )
39 #endif
40 #ifndef max
41 #define max(x,y)  ( (x) > (y) ? (x) : (y) )
42 #endif
43 
44 HEV update_event_sem;
45 HMTX bmp_mutex_sem;
46 
47 /* bitmap details */
48 typedef struct tagBM {
49     BOOL valid;
50     BOOL old_bmp;		/* bitmap type */
51     PBITMAPINFO2 pbmi;		/* pointer to bitmap info */
52     PBYTE bits;			/* pointer to bitmap bits */
53     int width;
54     int height;
55     int planes;
56     int depth;
57     int palsize;
58     int palimportant;
59     int old_width;
60     int old_height;
61     int old_planes;
62     int old_depth;
63     int old_palsize;
64     int old_palimportant;
65 } BMAP;
66 
67 typedef struct tagDISPLAY {
68     LONG planes;
69     LONG bitcount;
70     LONG hasPalMan;		/* Palette Manager */
71     BOOL hpal_exists;
72     HPAL hpal;
73 } DISPLAY;
74 
75 /* options that are saved in INI file */
76 typedef struct tagOPTIONS {
77     POINTL img_origin;
78     POINTL img_size;
79     BOOL img_max;
80 } OPTIONS;
81 
82 #define CW_USEDEFAULT 32768
83 
84 
85 BMAP bitmap;
86 DISPLAY display;
87 OPTIONS option;
88 PBYTE bbuffer;			/* for BMP file display */
89 POINTL scroll_pos;		/* not used *//* not used */
90 ULONG os_version;
91 char *section = "Ghostscript Image";
92 
93 HAB hab;			/* Anchor Block */
94 HWND hwnd_frame;
95 HWND hwnd_bmp;
96 HWND hwnd_gs;			/* window handle for CMD.EXE that started gs */
97 TID update_tid;
98 
99 #define WM_GSUPDATE WM_USER+1
100 #define SB_TOP 20
101 #define SB_BOTTOM 21
102 
103 
104 MRESULT EXPENTRY ClientWndProc(HWND, ULONG, MPARAM, MPARAM);
105 MRESULT EXPENTRY AboutDlgProc(HWND, ULONG, MPARAM, MPARAM);
106 APIRET init_window(void);
107 void fix_sysmenu(HWND);
108 APIRET restore_window_position(SWP * pswp);
109 BOOL scan_bitmap(BMAP * pbm);
110 void read_profile(void);
111 void write_profile(void);
112 APIRET init_display(int argc, char *argv[]);
113 APIRET init_bitmap(int argc, char *argv[]);
114 void copy_clipboard(void);
115 HBITMAP make_bitmap(BMAP * pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth);
116 
117 void
debugbeep(int type)118 debugbeep(int type)
119 {
120 #ifdef DEBUG
121     int i;
122 
123 /* current debug beeps are: */
124 /* 1. Null handle PS */
125 /* 2. make_bitmap() failed */
126 /* 3. GpiDrawBits() or WinDrawBitmap() failed */
127 /* 4. Null handle PS from WinBeginPaint() */
128     for (i = 0; i < type; i++) {
129 	DosBeep(400 + 100 * type, 50);
130 	DosSleep(50);
131     }
132 #endif
133 }
134 
135 
136 /* display message */
137 int
message_box(char * str,int icon)138 message_box(char *str, int icon)
139 {
140     return WinMessageBox(HWND_DESKTOP, hwnd_frame ? hwnd_frame : HWND_DESKTOP,
141 			 str, "gspmdrv.exe", 0, icon | MB_MOVEABLE | MB_OK);
142 }
143 
144 void
error_message(char * str)145 error_message(char *str)
146 {
147     WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "gspmdrv.exe", 0, MB_MOVEABLE | MB_ICONHAND | MB_OK);
148     WinPostMsg(hwnd_frame, WM_QUIT, MPFROMLONG(0), MPFROMLONG(0));
149 }
150 
151 /* Update thread */
152 /* This thread waits for the update event semaphore from gs.exe */
153 /* then generates a WM_PAINT message for the bitmap */
154 /* This thread must NOT call C library functions */
155 VOID APIENTRY
update_func(ULONG unused)156 update_func(ULONG unused)
157 {
158     APIRET rc;
159     BOOL flag;
160     ULONG count;
161 
162     unused = unused;		/* to shut up warning */
163     while (!DosQueryEventSem(update_event_sem, &count)) {
164 	/* loop while semaphore exists */
165 	DosWaitEventSem(update_event_sem, SEM_INDEFINITE_WAIT);
166 	DosResetEventSem(update_event_sem, &count);
167 	WinPostMsg(hwnd_bmp, WM_GSUPDATE, MPFROMLONG(0), MPFROMLONG(0));
168     }
169 }
170 
171 VOID APIENTRY
exit_func(ULONG code)172 exit_func(ULONG code)
173 {
174     write_profile();
175     DosCloseEventSem(update_event_sem);
176     DosCloseMutexSem(bmp_mutex_sem);
177     DosFreeMem((PVOID) bitmap.pbmi);
178     DosExitList(EXLST_EXIT, 0);
179     code = code;		/* to shut up warning */
180 }
181 
182 void
find_hwnd_gs(char * gsid)183 find_hwnd_gs(char *gsid)
184 {
185     ULONG ulCount;
186     ULONG ulLength;
187     ULONG pBase;
188     ULONG cbBuf;
189     PSWBLOCK pswblk;
190     PSWENTRY pswentry;
191     SWCNTRL *pswc;
192     int i;
193     ULONG pid;
194     char buf[256];
195     char *p, *s;
196     PTIB pptib;
197     PPIB pppib;
198 
199     /* extract gs pid from command line id */
200     strcpy(buf, gsid);
201     for (p = buf; *p && *p != '_'; p++);
202     *p++ = '\0';
203     s = p;
204     for (p = buf; *p && *p != '_'; p++);
205     *p = '\0';
206     pid = atoi(s);		/* pid is Process ID of CMD.EXE that started gsos2.exe */
207 
208     ulCount = WinQuerySwitchList(hab, NULL, 0);		/* get num of items */
209     cbBuf = (ulCount * sizeof(SWENTRY)) + sizeof(HSWITCH);
210     pswblk = (PSWBLOCK) malloc(cbBuf + 32768);
211     ulCount = WinQuerySwitchList(hab, pswblk, cbBuf);	/* get num of items */
212     for (i = 0; i < ulCount; i++) {
213 	pswentry = &pswblk->aswentry[i];
214 	pswc = &pswentry->swctl;
215 	if (pid == pswc->idProcess)
216 	    hwnd_gs = pswc->hwnd;	/* save window handle */
217     }
218 }
219 
220 
221 int
main(int argc,char * argv[])222 main(int argc, char *argv[])
223 {
224     HMQ hand_mq;		/* message queue */
225     QMSG q_mess;		/* message queue */
226     APIRET rc = 0;
227 
228 
229     hab = WinInitialize(0);	/* Get the Anchor Block */
230 
231     hand_mq = WinCreateMsgQueue(hab, 0);	/* start a queue */
232 
233     if (argc < 2) {
234 	rc = 1;
235 	error_message("Usage: gspmdrv -d id_string");
236     }
237     if (!rc) {
238 	if (strcmp(argv[1], "-d") == 0) {
239 	    rc = init_display(argc, argv);
240 	} else if (strcmp(argv[1], "-b") == 0) {
241 	    rc = init_bitmap(argc, argv);
242 	} else {
243 	    rc = 1;
244 	    error_message("Usage: gspmdrv -d id_string");
245 	}
246     }
247     if (!rc) {
248 	rc = DosCreateThread(&update_tid, update_func, 0, 0, 8192);
249 	if (rc)
250 	    error_message("Failed to create update thread");
251     }
252     if (!rc)
253 	rc = init_window();
254 
255     if (!rc)
256 	WinShowWindow(hwnd_frame, TRUE);
257 
258     if (!rc) {
259 	/* keep gspmdrv.exe in memory for number of minutes specified in */
260 	/* environment variable GS_LOAD */
261 	_emxload_env("GS_LOAD");
262     }
263     DosExitList(EXLST_ADD, exit_func);
264 
265     /* message loop */
266     while (!rc && WinGetMsg(hab, &q_mess, 0L, 0, 0))
267 	WinDispatchMsg(hab, &q_mess);
268 
269     /* Shut down the application window and queue */
270     DosKillThread(update_tid);
271     WinDestroyWindow(hwnd_frame);
272     WinDestroyMsgQueue(hand_mq);
273     WinTerminate(hab);
274     return rc;
275 }
276 
277 APIRET
init_window()278 init_window()
279 {
280     ULONG version[3];
281     SWP swp;
282     APIRET rc = 0;
283     ULONG flFlags;		/* Window frame definition */
284     unsigned char class[] = "gspmdrvClass";	/* class name */
285 
286     if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION, &version, sizeof(version)))
287 	os_version = 201000;	/* a guess */
288     else {
289 	os_version = version[0] * 10000 + version[1] * 100 + version[2];
290     }
291 
292     /* define the frame constants */
293     flFlags = FCF_TITLEBAR |	/* have a title bar */
294 	FCF_SIZEBORDER |	/* have a sizeable window */
295 	FCF_MINMAX |		/* have a min and max button */
296 	FCF_SYSMENU |		/* include a system menu */
297 	FCF_VERTSCROLL |	/* vertical scroll bar */
298 	FCF_HORZSCROLL |	/* horizontal scroll bar */
299 	FCF_TASKLIST |		/* show it in window list */
300 	FCF_ICON;		/* Load icon from resources */
301 
302     /* save SHELL default size and location */
303     rc = WinQueryTaskSizePos(hab, 0, &swp);
304     if (rc)
305 	return rc;
306 
307     read_profile();
308     if ((option.img_size.x == 0) || (option.img_size.y == 0))
309 	option.img_size.x = option.img_size.y = CW_USEDEFAULT;
310 
311     if (!rc) {
312 	HPS ps = WinGetPS(HWND_DESKTOP);
313 	HDC hdc = GpiQueryDevice(ps);
314 
315 	DevQueryCaps(hdc, CAPS_COLOR_PLANES, 1, &display.planes);
316 	DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &display.bitcount);
317 	DevQueryCaps(hdc, CAPS_ADDITIONAL_GRAPHICS, 1, &display.hasPalMan);
318 	display.hasPalMan &= CAPS_PALETTE_MANAGER;
319 	WinReleasePS(ps);
320     }
321     if (!rc) {
322 	if (!WinRegisterClass(	/* register this window class */
323 				 hab,	/* anchor block */
324 				 (PSZ) class,	/* class name */
325 				 (PFNWP) ClientWndProc,		/* window function */
326 				 CS_SIZEREDRAW |	/* window style */
327 				 CS_MOVENOTIFY,
328 				 0))	/* no storage */
329 	    exit(1);
330 
331 	hwnd_frame = WinCreateStdWindow(
332 					   HWND_DESKTOP,	/* window type */
333 					   0,	/* frame style is not WS_VISIBLE */
334 					   &flFlags,	/* definitions */
335 					   (PSZ) class,		/* client class */
336 					   (PSZ) "Ghostscript Image",	/* title */
337 					   WS_VISIBLE,	/* client style */
338 					   0,	/* resource module */
339 					   ID_GSPMDRV,	/* resource identifier */
340 					   &hwnd_bmp);	/* pointer to client */
341 
342 	fix_sysmenu(hwnd_frame);
343     }
344     rc = restore_window_position(&swp);
345 
346     return rc;
347 }
348 
349 
350 void
write_profile(void)351 write_profile(void)
352 {
353     char profile[64];
354 
355     sprintf(profile, "%d %d", option.img_origin.x, option.img_origin.y);
356     PrfWriteProfileString(HINI_USERPROFILE, section, "Origin", profile);
357     sprintf(profile, "%d %d", option.img_size.x, option.img_size.y);
358     PrfWriteProfileString(HINI_USERPROFILE, section, "Size", profile);
359     sprintf(profile, "%d", option.img_max);
360     PrfWriteProfileString(HINI_USERPROFILE, section, "Maximized", profile);
361 }
362 
363 void
read_profile(void)364 read_profile(void)
365 {
366     char profile[64];
367 
368     PrfQueryProfileString(HINI_USERPROFILE, section, "Origin", "", profile, sizeof(profile));
369     if (sscanf(profile, "%d %d", &option.img_origin.x, &option.img_origin.y) != 2) {
370 	option.img_origin.x = CW_USEDEFAULT;
371 	option.img_origin.y = CW_USEDEFAULT;
372     }
373     PrfQueryProfileString(HINI_USERPROFILE, section, "Size", "", profile, sizeof(profile));
374     if (sscanf(profile, "%d %d", &option.img_size.x, &option.img_size.y) != 2) {
375 	option.img_size.x = CW_USEDEFAULT;
376 	option.img_size.y = CW_USEDEFAULT;
377     }
378     PrfQueryProfileString(HINI_USERPROFILE, section, "Maximized", "", profile, sizeof(profile));
379     if (sscanf(profile, "%d", &option.img_max) != 1)
380 	option.img_max = 0;
381 }
382 
383 void
fix_sysmenu(HWND hwnd)384 fix_sysmenu(HWND hwnd)
385 {
386     MENUITEM mi;
387     HWND hwndSysMenu;
388 
389     if (!WinSendMsg(WinWindowFromID(hwnd, FID_SYSMENU), MM_QUERYITEM,
390 		    MPFROM2SHORT(SC_SYSMENU, TRUE), MPFROMP(&mi))) {
391 	message_box("failed getting system menu handle", 0);
392 	return;
393     }
394     hwndSysMenu = mi.hwndSubMenu;
395     mi.iPosition = MIT_END;
396     mi.afStyle = MIS_SEPARATOR;
397     mi.afAttribute = 0;
398     mi.id = 0;
399     mi.hwndSubMenu = 0;
400     mi.hItem = 0;
401     WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), NULL);
402     mi.afStyle = MIS_TEXT;
403     mi.id = IDM_ABOUT;
404     WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "About...");
405     mi.id = IDM_COPY;
406     WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "Copy");
407 }
408 
409 APIRET
restore_window_position(SWP * pswp)410 restore_window_position(SWP * pswp)
411 {
412     SWP swp;
413 
414     swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW;
415 
416     if (option.img_max) {
417 	/* Get maximized frame window position and size. */
418 	if (!WinGetMaxPosition(hwnd_frame, &swp))
419 	    return 1;
420 	swp.fl |= SWP_MAXIMIZE;
421     } else if ((option.img_size.x != CW_USEDEFAULT) &&
422 	       (option.img_size.y != CW_USEDEFAULT) &&
423 	       (option.img_origin.y != CW_USEDEFAULT) &&
424 	       (option.img_origin.y != CW_USEDEFAULT)) {
425 	LONG cxClientMax;
426 	LONG cyClientMax;
427 	LONG cyTitleBar;
428 	LONG cxSizeBorder;
429 	LONG cySizeBorder;
430 
431 	/* get maximum client window size */
432 	cxClientMax = WinQuerySysValue(HWND_DESKTOP, SV_CXFULLSCREEN);
433 	cyClientMax = WinQuerySysValue(HWND_DESKTOP, SV_CYFULLSCREEN);
434 	cyTitleBar = WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR);
435 	cxSizeBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);
436 	cySizeBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);
437 	cyClientMax += cyTitleBar;
438 
439 	/* Make sure x origin is within display boundaries */
440 	swp.x = option.img_origin.x;
441 	if (swp.x < -cxSizeBorder)
442 	    swp.x = 0;
443 
444 	/* Make sure window isn't too wide, or negative value */
445 	swp.cx = option.img_size.x;
446 	if (swp.cx >= cxClientMax || swp.cx < 0) {
447 	    swp.cx = cxClientMax;
448 	    swp.x = 0;
449 	}
450 	if ((swp.x + swp.cx) > (cxClientMax + cxSizeBorder))
451 	    swp.x = cxClientMax + cxSizeBorder - swp.cx;
452 
453 	/* Make sure y origin is within display boundaries */
454 	swp.y = option.img_origin.y;
455 	if (swp.y < -cySizeBorder)
456 	    swp.y = 0;
457 
458 	/* Make sure window isn't too high, or negative value */
459 	swp.cy = option.img_size.y;
460 	if (swp.cy > cyClientMax || swp.cy < 0) {
461 	    swp.cy = cyClientMax;
462 	    swp.y = 0;
463 	}
464 	if ((swp.y + swp.cy) > (cyClientMax + cySizeBorder))
465 	    swp.y = cyClientMax + cySizeBorder - swp.cy;
466     } else {			/* No saved position -- use supplied position */
467 	swp = *pswp;
468 	option.img_origin.x = swp.x;
469 	option.img_origin.y = swp.y;
470 	option.img_size.x = swp.cx;
471 	option.img_size.y = swp.cy;
472 	option.img_max = FALSE;
473 	swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW;
474     }
475 
476     if (hwnd_gs)
477 	swp.fl |= SWP_ZORDER;
478     /* Position and size this frame window */
479     if (!WinSetWindowPos(hwnd_frame, hwnd_gs,
480 			 swp.x, swp.y, swp.cx, swp.cy, swp.fl))
481 	return 1;
482     return 0;
483 }
484 
485 APIRET
init_display(int argc,char * argv[])486 init_display(int argc, char *argv[])
487 {
488     char buf[256];
489     char name[256];
490     APIRET rc = 0;
491 
492     if (argc != 3) {
493 	rc = 1;
494 	error_message("Usage: gspmdrv -d id_string");
495     }
496     find_hwnd_gs(argv[2]);
497 
498     if (!rc) {
499 	sprintf(name, SHARED_NAME, argv[2]);
500 	rc = DosGetNamedSharedMem((PVOID *) & bitmap.pbmi, name, PAG_READ | PAG_WRITE);
501 	if (rc) {
502 	    sprintf(buf, "Failed to open: bmp shared memory \"%s\" rc = %d", argv[0], rc);
503 	    error_message(buf);
504 	}
505     }
506     if (!rc) {
507 	sprintf(name, SYNC_NAME, argv[2]);
508 	rc = DosOpenEventSem(name, &update_event_sem);
509 	if (rc) {
510 	    sprintf(buf, "Failed to open: update event semaphore \"%s\" rc = %d", argv[1], rc);
511 	    error_message(buf);
512 	}
513     }
514     if (!rc) {
515 	sprintf(name, MUTEX_NAME, argv[2]);
516 	rc = DosOpenMutexSem(name, &bmp_mutex_sem);
517 	if (rc) {
518 	    sprintf(buf, "Failed to open: bmp mutex semaphore \"%s\" rc = %d", argv[1], rc);
519 	    error_message(buf);
520 	}
521     }
522     if (!rc) {
523 	scan_bitmap(&bitmap);
524 	bitmap.valid = TRUE;
525     }
526     return rc;
527 }
528 
529 
530 APIRET
init_bitmap(int argc,char * argv[])531 init_bitmap(int argc, char *argv[])
532 {
533     char buf[256];
534     APIRET rc = 0;
535     HFILE hf;
536     ULONG action, count, length;
537     PBITMAPFILEHEADER2 pbmfh;
538 
539     if (argc != 3)
540 	return 1;		/* error - no filename */
541 
542     /* open bitmap */
543     if ((rc = DosOpen(argv[2], &hf, &action, 0, FILE_NORMAL, FILE_OPEN,
544 		      OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE, 0))
545 	!= (APIRET) 0) {
546 	sprintf(buf, "Error opening: %s", argv[2]);
547 	error_message(buf);
548 	return rc;
549     }
550     rc = DosSetFilePtr(hf, 0, FILE_END, &length);
551     if (rc) {
552 	sprintf(buf, "failed seeking to EOF: error = %d", rc);
553 	error_message(buf);
554 	return rc;
555     }
556     rc = DosSetFilePtr(hf, 0, FILE_BEGIN, &count);
557     if (rc) {
558 	sprintf(buf, "failed seeking to BOF: error = %d", rc);
559 	error_message(buf);
560 	return rc;
561     };
562 
563     /* allocate memory for bitmap */
564     if ((rc = DosAllocMem((PPVOID) & bbuffer, length, PAG_READ | PAG_WRITE | PAG_COMMIT))
565 	!= (APIRET) 0) {
566 	sprintf(buf, "failed allocating memory");
567 	error_message(buf);
568 	return rc;
569     }
570     rc = DosRead(hf, bbuffer, length, &count);
571     DosClose(hf);
572     if (rc) {
573 	sprintf(buf, "failed reading bitmap, error = %u, count = %u", rc, count);
574 	error_message(buf);
575 	return rc;
576     }
577     /* extract some info about bitmap */
578     pbmfh = (PBITMAPFILEHEADER2) bbuffer;
579     bitmap.pbmi = (PBITMAPINFO2) (&pbmfh->bmp2);
580 
581     scan_bitmap(&bitmap);
582     bitmap.valid = TRUE;
583 
584     sprintf(buf, "bitmap width = %d, height = %d", bitmap.width, bitmap.height);
585     message_box(buf, 0);
586     return rc;
587 }
588 
589 #define MAX_PAL_SIZE 256
590 void
make_palette(BMAP * pbm)591 make_palette(BMAP * pbm)
592 {
593     ULONG tbl[MAX_PAL_SIZE];
594     PRGB2 palptr = (PRGB2) ((PBYTE) (pbm->pbmi) + pbm->pbmi->cbFix);
595     RGB *old_palptr = (RGB *) palptr;
596     int palcount = pbm->palimportant;
597     int i;
598     BOOL old_bmp = (pbm->pbmi->cbFix == sizeof(BITMAPINFOHEADER));
599 
600     if (old_bmp) {
601 	for (i = 0; i < palcount; i++) {
602 	    tbl[i] = (old_palptr->bRed << 16) + (old_palptr->bGreen << 8) + (old_palptr->bBlue);
603 	    palptr++;
604 	}
605     } else {
606 	for (i = 0; i < palcount; i++) {
607 	    tbl[i] = (palptr->bRed << 16) + (palptr->bGreen << 8) + (palptr->bBlue);
608 	    palptr++;
609 	}
610     }
611     if (display.hpal_exists)
612 	GpiDeletePalette(display.hpal);
613     display.hpal = GpiCreatePalette(hab, 0L, LCOLF_CONSECRGB, palcount, tbl);
614     display.hpal_exists = TRUE;
615 }
616 
617 
618 
619 /* scan bitmap */
620 /* update bitmap structure */
621 /* return value is TRUE if bitmap dimension has changed */
622 BOOL
scan_bitmap(BMAP * pbm)623 scan_bitmap(BMAP * pbm)
624 {
625     PBITMAPINFO2 pbmi = pbm->pbmi;
626     PBITMAPINFO old_pbmi = (PBITMAPINFO) pbmi;
627     BOOL old_bmp = (pbmi->cbFix == sizeof(BITMAPINFOHEADER));
628 
629     if (old_bmp) {
630 	/* it is a BITMAPINFO */
631 	switch (old_pbmi->cBitCount) {
632 	    case 24:
633 		pbm->palsize = 0;
634 		break;
635 	    case 8:
636 		pbm->palsize = 256;
637 		break;
638 	    case 4:
639 		pbm->palsize = 16;
640 		break;
641 	    case 1:
642 		pbm->palsize = 2;
643 		break;
644 	    default:
645 		pbm->valid = FALSE;
646 		error_message("scan_bitmap: wrong number of bits");	/* panic */
647 		return FALSE;
648 	}
649 	pbm->palimportant = pbm->palsize;
650 	pbm->palsize = pbm->palsize * sizeof(RGB);
651 	pbm->bits = (PBYTE) old_pbmi + old_pbmi->cbFix + pbm->palsize;
652 	pbm->width = old_pbmi->cx;
653 	pbm->height = old_pbmi->cy;
654 	pbm->planes = old_pbmi->cPlanes;
655 	pbm->depth = old_pbmi->cBitCount;
656     } else {
657 	/* it is a BITMAPINFO2 */
658 	switch (pbmi->cBitCount) {
659 	    case 24:
660 		pbm->palsize = 0;
661 		break;
662 	    case 8:
663 		pbm->palsize = 256;
664 		break;
665 	    case 4:
666 		pbm->palsize = 16;
667 		break;
668 	    case 1:
669 		pbm->palsize = 2;
670 		break;
671 	    default:
672 		pbm->valid = FALSE;
673 		error_message("scan_bitmap: wrong number of bits");	/* panic */
674 		return FALSE;
675 	}
676 	if ((pbmi->cbFix > (&(pbmi->cclrUsed) - &(pbmi->cbFix)))
677 	    && (pbmi->cclrUsed != 0) && (pbmi->cBitCount != 24))
678 	    pbm->palsize = pbmi->cclrUsed;
679 	pbm->palimportant = pbm->palsize;
680 	if ((pbmi->cbFix > (&(pbmi->cclrImportant) - &(pbmi->cbFix)))
681 	    && (pbmi->cclrImportant != 0) && (pbmi->cBitCount != 24))
682 	    pbm->palimportant = pbmi->cclrImportant;
683 	pbm->palsize = pbm->palsize * sizeof(RGB2);
684 	pbm->bits = (PBYTE) pbmi + pbmi->cbFix + pbm->palsize;
685 	pbm->width = pbmi->cx;
686 	pbm->height = pbmi->cy;
687 	pbm->planes = pbmi->cPlanes;
688 	pbm->depth = pbmi->cBitCount;
689     }
690 
691     if ((pbm->palsize != pbm->old_palsize) || (pbm->palimportant != pbm->old_palimportant)) {
692 	if ((pbm->depth == 8) && display.hasPalMan)
693 	    make_palette(pbm);
694 	pbm->old_palimportant = pbm->palimportant;
695     }
696     if ((pbm->width == pbm->old_width) &&
697 	(pbm->height == pbm->old_height) &&
698 	(pbm->planes == pbm->old_planes) &&
699 	(pbm->depth == pbm->old_depth) &&
700 	(pbm->palsize == pbm->old_palsize) &&
701 	(pbm->old_bmp == old_bmp))
702 	return FALSE;
703 
704     /* bitmap has changed */
705     pbm->old_width = pbm->width;
706     pbm->old_height = pbm->height;
707     pbm->old_planes = pbm->planes;
708     pbm->old_depth = pbm->depth;
709     pbm->old_palsize = pbm->palsize;
710     pbm->old_bmp = old_bmp;
711     return TRUE;
712 }
713 
714 
715 void
update_scroll_bars(void)716 update_scroll_bars(void)
717 {
718     /* Cause update of scroll bars etc. */
719     SWP swp;
720 
721     WinQueryWindowPos(hwnd_bmp, &swp);
722     WinSendMsg(hwnd_bmp, WM_SIZE, MPFROM2SHORT(swp.cx, swp.cy), MPFROM2SHORT(swp.cx, swp.cy));
723 }
724 
725 
726 /* copy bitmap to the clipboard */
727 void
copy_clipboard(void)728 copy_clipboard(void)
729 {
730     HBITMAP hbmp;
731 
732     if (!bitmap.valid) {
733 	message_box("Cannot copy to clipboard:\nNo Bitmap displayed", 0);
734 	return;
735     }
736     if (WinOpenClipbrd(hab)) {
737 	/* get bmp mutex to stop gs.exe changing bitmap while we copy it */
738 	DosRequestMutexSem(bmp_mutex_sem, 10000);
739 	if (scan_bitmap(&bitmap)) {
740 	    /* bitmap has changed */
741 	    update_scroll_bars();
742 	}
743 	hbmp = make_bitmap(&bitmap, 0, 0, bitmap.width, bitmap.height, bitmap.depth);
744 	if (hbmp) {
745 	    WinEmptyClipbrd(hab);
746 	    WinSetClipbrdData(hab, (ULONG) hbmp, CF_BITMAP, CFI_HANDLE);
747 	}
748 	DosReleaseMutexSem(bmp_mutex_sem);
749 	WinCloseClipbrd(hab);
750     }
751 }
752 
753 
754 HBITMAP
make_bitmap(BMAP * pbm,ULONG left,ULONG bottom,ULONG right,ULONG top,ULONG depth)755 make_bitmap(BMAP * pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth)
756 {
757     HDC hdc = DEV_ERROR, hdcMem = DEV_ERROR;
758     HPS hps = GPI_ERROR;
759     HBITMAP hbmp = GPI_ERROR, hbmr = HBM_ERROR;
760     SIZEL sizePS;
761     BITMAPINFOHEADER2 bmih;
762 
763     if ((left == right) || (bottom == top))
764 	return (HBITMAP) NULL;
765 
766     if (right > pbm->width)
767 	right = pbm->width;
768     if (left > pbm->width)
769 	left = 0;
770     if (top > pbm->height)
771 	top = pbm->height;
772     if (bottom > pbm->height)
773 	bottom = 0;
774 
775     memset(&bmih, 0, sizeof(bmih));
776     bmih.cbFix = sizeof(BITMAPINFOHEADER2);
777     bmih.cx = right - left;
778     bmih.cy = top - bottom;
779     bmih.cPlanes = 1;
780     bmih.cBitCount = depth;
781 
782     /* create memory DC compatible with screen */
783     hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 0L, NULL, NULLHANDLE);
784 
785     sizePS.cx = right - left;
786     sizePS.cy = top - bottom;
787     if (hdcMem != DEV_ERROR)
788 	hps = GpiCreatePS(hab, hdcMem, &sizePS,
789 			  PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
790 
791     if (hps != GPI_ERROR)
792 	hbmp = GpiCreateBitmap(hps, &bmih, 0L, NULL, NULL);
793 
794     if (hbmp != GPI_ERROR)
795 	hbmr = GpiSetBitmap(hps, hbmp);
796 
797 
798     if (hbmr != HBM_ERROR) {
799 	LONG rc;
800 	ERRORID eid;
801 	POINTL apts[4];
802 
803 	/* target is inclusive */
804 	apts[0].x = 0;
805 	apts[0].y = 0;
806 	apts[1].x = right - left - 1;
807 	apts[1].y = top - bottom - 1;
808 	/* source is not inclusive of top & right borders */
809 	apts[2].x = left;
810 	apts[2].y = bottom;
811 	apts[3].x = right;
812 	apts[3].y = top;
813 
814 	rc = 0;
815 	eid = WinGetLastError(hab);
816 	rc = GpiDrawBits(hps, pbm->bits, pbm->pbmi, 4, apts,
817 		     (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
818 	if (rc == 0) {
819 	    char buf[256];
820 
821 	    eid = WinGetLastError(hab);
822 	    sprintf(buf, "make_bitmap: GpiDrawBits rc = %08x, eid = %08x", rc, eid);
823 	    message_box(buf, 0);
824 	}
825     }
826     if (hbmr != HBM_ERROR)
827 	GpiSetBitmap(hps, (ULONG) 0);
828     if (hps != GPI_ERROR)
829 	GpiDestroyPS(hps);
830     if (hdcMem != DEV_ERROR)
831 	DevCloseDC(hdcMem);
832 
833     if ((hbmr == HBM_ERROR) || (hdcMem == DEV_ERROR) ||
834 	(hbmp == GPI_ERROR) || (hps == GPI_ERROR)) {
835 	if (hbmp != GPI_ERROR)
836 	    GpiDeleteBitmap(hbmp);
837 	debugbeep(2);
838 	return 0;
839     }
840     return hbmp;
841 }
842 
843 MRESULT
paint_bitmap(HPS ps,PRECTL prect,int scrollx,int scrolly)844 paint_bitmap(HPS ps, PRECTL prect, int scrollx, int scrolly)
845 {
846     POINTL apts[4];
847     int wx, wy;
848 
849     if (WinIsRectEmpty(hab, prect))
850 	return 0;
851     if (ps == NULLHANDLE) {
852 	debugbeep(1);
853     }
854     /* source is not inclusive of top & right borders */
855     wx = prect->xRight - prect->xLeft;	/* update width */
856     wy = prect->yTop - prect->yBottom;	/* update height */
857     apts[2].x = prect->xLeft + scrollx;
858     apts[2].y = prect->yBottom + scrolly;
859     if (apts[2].x > bitmap.width)
860 	apts[2].x = bitmap.width;
861     if (apts[2].x + wx > bitmap.width)
862 	wx = bitmap.width - apts[2].x;
863     apts[3].x = apts[2].x + wx;
864     if (apts[2].y > bitmap.height)
865 	apts[2].y = bitmap.height;
866     if (apts[2].y + wy > bitmap.height)
867 	wy = bitmap.height - apts[2].y;
868     apts[3].y = apts[2].y + wy;
869     /* target is inclusive */
870     apts[0].x = prect->xLeft;
871     apts[0].y = prect->yBottom;
872     apts[1].x = prect->xLeft + wx - 1;
873     apts[1].y = prect->yBottom + wy - 1;
874 
875     if ((display.bitcount == 4)	/* standard VGA is buggy */
876 	||((os_version == 201100) && (display.bitcount == 8) && (bitmap.depth == 1))	/* S3 and ATI GU are buggy */
877 	) {
878 	/* slow code to dodge OS/2 bugs */
879 	/* this code double buffers the bitmap and works on a standard VGA
880 	 * but didn't work on an ATI Ultra Graphics Pro in 8514 emulation
881 	 */
882 	/* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 8bit/pixel bitmap */
883 	HBITMAP hbmp;
884 
885 	/* create a bitmap */
886 	hbmp = make_bitmap(&bitmap, apts[2].x, apts[2].y, apts[3].x, apts[3].y, bitmap.depth);
887 	/* Draw it to the display */
888 	if (hbmp) {
889 	    WinDrawBitmap(ps, hbmp, NULL, &apts[0], CLR_BLACK, CLR_WHITE, DBM_NORMAL);
890 	    GpiDeleteBitmap(hbmp);
891 	}
892     } else {
893 	/* fast code which doesn't always work */
894 	/* This code works on the Trident SVGA and 8514 in 256 color mode,
895 	 * but GpiDrawBits fails with a SYS3175 on the standard VGA.
896 	 */
897 	/* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 1bit/pixel bitmap */
898 	GpiDrawBits(ps, bitmap.bits, bitmap.pbmi, 4, apts,
899 		    (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
900     }
901 
902     return 0;
903 }
904 
905 
906 /* This is the window function */
907 MRESULT EXPENTRY
ClientWndProc(HWND hwnd,ULONG mess,MPARAM mp1,MPARAM mp2)908 ClientWndProc(HWND hwnd, ULONG mess,
909 	      MPARAM mp1, MPARAM mp2)
910 {
911     char buf[256];
912     static int cxClient, cyClient;
913     static int cxAdjust, cyAdjust;
914     static int nHscrollMax, nHscrollPos;
915     static int nVscrollMax, nVscrollPos;
916     int nHscrollInc;
917     int nVscrollInc;
918     HWND hwndScroll;
919     HPS hps;
920     RECTL rect;
921     ULONG ulclr;
922 
923     switch (mess) {
924 	case WM_CREATE:
925 	    break;
926 	case WM_ERASEBACKGROUND:
927 	    /* by returning TRUE, the Presentation Manager automatically clears
928 	     * the window each time the window is resized or moved.
929 	     */
930 	    return (MRESULT) TRUE;
931 	case WM_GSUPDATE:
932 	    if (!WinInvalidateRect(hwnd_bmp, (PRECTL) NULL, TRUE))
933 		error_message("error invalidating rect");
934 	    if (!WinUpdateWindow(hwnd_bmp))
935 		error_message("error updating window");
936 	    return 0;
937 	case WM_COMMAND:
938 	    switch (LONGFROMMP(mp1)) {
939 		case IDM_ABOUT:
940 		    WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, 0, IDD_ABOUT, 0);
941 		    break;
942 		case IDM_COPY:
943 		    copy_clipboard();
944 		    break;
945 	    }
946 	    break;
947 	case WM_REALIZEPALETTE:
948 	    if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
949 		hps = WinGetPS(hwnd);
950 		if (hps == NULLHANDLE)
951 		    debugbeep(1);
952 		GpiSelectPalette(hps, display.hpal);
953 		if (WinRealizePalette(hwnd, hps, &ulclr) > 0)
954 		    WinInvalidateRect(hwnd, NULL, FALSE);
955 		GpiSelectPalette(hps, (HPAL) NULL);
956 		WinReleasePS(hps);
957 		return 0;
958 	    }
959 	    break;		/* use default processing */
960 	case WM_PAINT:
961 	    /* Refresh the window each time the WM_PAINT message is received */
962 
963 	    /* get bmp mutex to stop gs.exe changing bitmap while we paint */
964 	    DosRequestMutexSem(bmp_mutex_sem, 10000);
965 	    if (scan_bitmap(&bitmap))
966 		update_scroll_bars();	/* bitmap has changed */
967 
968 	    if (!bitmap.valid) {
969 		DosReleaseMutexSem(bmp_mutex_sem);
970 		hps = WinBeginPaint(hwnd, (ULONG) 0, &rect);
971 		if (hps == NULLHANDLE)
972 		    debugbeep(4);
973 		WinFillRect(hps, &rect, CLR_BACKGROUND);
974 		WinEndPaint(hwnd);
975 		return 0;
976 	    }
977 	    hps = WinBeginPaint(hwnd, (HPS) NULL, &rect);
978 	    if (hps == NULLHANDLE)
979 		debugbeep(4);
980 	    if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
981 		GpiSelectPalette(hps, display.hpal);
982 		WinRealizePalette(hwnd, hps, &ulclr);
983 		paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
984 		GpiSelectPalette(hps, (HPAL) NULL);
985 	    } else
986 		paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
987 	    WinEndPaint(hwnd);
988 
989 	    DosReleaseMutexSem(bmp_mutex_sem);
990 	    return 0;
991 	case WM_MOVE:
992 	    /* don't interrogate the window location immediately since */
993 	    /* it causes the Diamond Stealth VL24 with IBM S3 drivers */
994 	    /* to corrupt the display */
995 	    DosSleep(50);
996 	    if (hwnd_frame) {	/* save window position for INI file */
997 		SWP swp;
998 
999 		WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
1000 		if (!(swp.fl & SWP_MINIMIZE)) {
1001 		    option.img_origin.x = swp.x;
1002 		    option.img_origin.y = swp.y;
1003 		    option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
1004 		}
1005 	    }
1006 	    return 0;
1007 	case WM_SIZE:
1008 	    cyClient = SHORT2FROMMP(mp2);
1009 	    cxClient = SHORT1FROMMP(mp2);
1010 
1011 	    cyAdjust = min(bitmap.height, cyClient) - cyClient;
1012 	    cyClient += cyAdjust;
1013 
1014 	    nVscrollMax = max(0, bitmap.height - cyClient);
1015 	    nVscrollPos = min(nVscrollPos, nVscrollMax);
1016 	    scroll_pos.y = nVscrollMax - nVscrollPos;
1017 
1018 	    if (!bitmap.valid)
1019 		cyClient = cyAdjust = nVscrollMax = nVscrollPos;
1020 
1021 	    hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
1022 	    WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nVscrollPos),
1023 		       MPFROM2SHORT(0, nVscrollMax));
1024 	    if (bitmap.valid)
1025 		WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cyClient, bitmap.height),
1026 			   MPFROMLONG(0));
1027 	    else
1028 		WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
1029 			   MPFROMLONG(0));
1030 
1031 	    cxAdjust = min(bitmap.width, cxClient) - cxClient;
1032 	    cxClient += cxAdjust;
1033 
1034 	    nHscrollMax = max(0, bitmap.width - cxClient);
1035 	    nHscrollPos = min(nHscrollPos, nHscrollMax);
1036 	    scroll_pos.x = nHscrollPos;
1037 
1038 	    if (!bitmap.valid)
1039 		cxClient = cxAdjust = nHscrollMax = nHscrollPos;
1040 
1041 	    hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
1042 	    WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nHscrollPos),
1043 		       MPFROM2SHORT(0, nHscrollMax));
1044 	    if (bitmap.valid)
1045 		WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cxClient, bitmap.width),
1046 			   MPFROMLONG(0));
1047 	    else
1048 		WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
1049 			   MPFROMLONG(0));
1050 
1051 	    if ((cxAdjust != 0 || cyAdjust != 0)) {
1052 		SWP swp;
1053 
1054 		WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
1055 		WinSetWindowPos(WinQueryWindow(hwnd, QW_PARENT), 0,
1056 				swp.x, swp.y - cyAdjust,
1057 		 swp.cx + cxAdjust, swp.cy + cyAdjust, SWP_SIZE | SWP_MOVE);
1058 		cxAdjust = cyAdjust = 0;
1059 	    }
1060 	    if (hwnd_frame) {	/* save window size for INI file */
1061 		SWP swp;
1062 
1063 		WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
1064 		if (!(swp.fl & SWP_MINIMIZE)) {
1065 		    option.img_size.x = swp.cx;
1066 		    option.img_size.y = swp.cy;
1067 		    option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
1068 		}
1069 	    }
1070 	    break;
1071 	case WM_VSCROLL:
1072 	    switch (SHORT2FROMMP(mp2)) {
1073 		case SB_LINEUP:
1074 		    nVscrollInc = -cyClient / 16;
1075 		    break;
1076 		case SB_LINEDOWN:
1077 		    nVscrollInc = cyClient / 16;
1078 		    break;
1079 		case SB_PAGEUP:
1080 		    nVscrollInc = min(-1, -cyClient);
1081 		    break;
1082 		case SB_PAGEDOWN:
1083 		    nVscrollInc = max(1, cyClient);
1084 		    break;
1085 		case SB_SLIDERPOSITION:
1086 		    nVscrollInc = SHORT1FROMMP(mp2) - nVscrollPos;
1087 		    break;
1088 		case SB_TOP:
1089 		    nVscrollInc = -nVscrollPos;
1090 		    break;
1091 		case SB_BOTTOM:
1092 		    nVscrollInc = nVscrollMax - nVscrollPos;
1093 		    break;
1094 		default:
1095 		    nVscrollInc = 0;
1096 	    }
1097 	    if ((nVscrollInc = max(-nVscrollPos,
1098 		       min(nVscrollInc, nVscrollMax - nVscrollPos))) != 0) {
1099 		LONG lComplexity;
1100 
1101 		hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
1102 		nVscrollPos += nVscrollInc;
1103 		scroll_pos.y = nVscrollMax - nVscrollPos;
1104 		lComplexity = WinScrollWindow(hwnd, 0, nVscrollInc, (PRECTL) NULL, (PRECTL) NULL,
1105 				     (HRGN) NULLHANDLE, (PRECTL) & rect, 0);
1106 		WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nVscrollPos), 0);
1107 		if (lComplexity != RGN_RECT) {
1108 		    WinInvalidateRect(hwnd, (PRECTL) NULL, FALSE);
1109 		    WinUpdateWindow(hwnd);
1110 		} else {
1111 		    /* redraw exposed area */
1112 		    hps = WinGetPS(hwnd);
1113 		    if (hps == NULLHANDLE)
1114 			debugbeep(1);
1115 		    if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
1116 			GpiSelectPalette(hps, display.hpal);
1117 			WinRealizePalette(hwnd, hps, &ulclr);
1118 			paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
1119 			GpiSelectPalette(hps, (HPAL) NULL);
1120 		    } else
1121 			paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
1122 		    WinReleasePS(hps);
1123 		}
1124 	    }
1125 	    break;
1126 	case WM_HSCROLL:
1127 	    switch (SHORT2FROMMP(mp2)) {
1128 		case SB_LINELEFT:
1129 		    nHscrollInc = -cxClient / 16;
1130 		    break;
1131 		case SB_LINERIGHT:
1132 		    nHscrollInc = cyClient / 16;
1133 		    break;
1134 		case SB_PAGELEFT:
1135 		    nHscrollInc = min(-1, -cxClient);
1136 		    break;
1137 		case SB_PAGERIGHT:
1138 		    nHscrollInc = max(1, cxClient);
1139 		    break;
1140 		case SB_SLIDERPOSITION:
1141 		    nHscrollInc = SHORT1FROMMP(mp2) - nHscrollPos;
1142 		    break;
1143 		default:
1144 		    nHscrollInc = 0;
1145 	    }
1146 	    if ((nHscrollInc = max(-nHscrollPos,
1147 		       min(nHscrollInc, nHscrollMax - nHscrollPos))) != 0) {
1148 		LONG lComplexity;
1149 
1150 		hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
1151 		nHscrollPos += nHscrollInc;
1152 		scroll_pos.x = nHscrollPos;
1153 		lComplexity = WinScrollWindow(hwnd, -nHscrollInc, 0, (PRECTL) NULL, (PRECTL) NULL,
1154 				     (HRGN) NULLHANDLE, (PRECTL) & rect, 0);
1155 		/* need to send next message BEFORE redrawing, otherwise S3 driver screws up */
1156 		WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nHscrollPos), 0);
1157 		if (lComplexity != RGN_RECT) {
1158 		    WinInvalidateRect(hwnd, (PRECTL) NULL, FALSE);
1159 		    WinUpdateWindow(hwnd);
1160 		} else {
1161 		    /* redraw exposed area */
1162 		    hps = WinGetPS(hwnd);
1163 		    if (hps == NULLHANDLE)
1164 			debugbeep(1);
1165 		    if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
1166 			GpiSelectPalette(hps, display.hpal);
1167 			WinRealizePalette(hwnd, hps, &ulclr);
1168 			paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
1169 			GpiSelectPalette(hps, (HPAL) NULL);
1170 		    } else
1171 			paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
1172 		    WinReleasePS(hps);
1173 		}
1174 	    }
1175 	    break;
1176 	case WM_CHAR:		/* process keystrokes here */
1177 	    if (SHORT1FROMMP(mp1) & KC_CHAR) {
1178 		/* pass control to gs if ENTER pressed */
1179 		if (hwnd_gs && (SHORT1FROMMP(mp2) == '\r'))
1180 		    WinSetActiveWindow(HWND_DESKTOP, hwnd_gs);
1181 	    }
1182 	    /* Process only key presses, not key releases */
1183 	    if (SHORT1FROMMP(mp1) & KC_KEYUP)
1184 		break;
1185 	    if (SHORT1FROMMP(mp1) & KC_VIRTUALKEY) {
1186 		USHORT vkey = SHORT2FROMMP(mp2);
1187 
1188 		switch (vkey) {
1189 		    case VK_HOME:
1190 			WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_TOP));
1191 			break;
1192 		    case VK_END:
1193 			WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_BOTTOM));
1194 			break;
1195 		    case VK_UP:
1196 			WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEUP));
1197 			break;
1198 		    case VK_DOWN:
1199 			WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEDOWN));
1200 			break;
1201 		    case VK_PAGEUP:
1202 			WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEUP));
1203 			break;
1204 		    case VK_PAGEDOWN:
1205 			WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEDOWN));
1206 			break;
1207 		    case VK_LEFT:
1208 			if (SHORT1FROMMP(mp1) & KC_CTRL)
1209 			    WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGELEFT));
1210 			else
1211 			    WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINELEFT));
1212 			break;
1213 		    case VK_RIGHT:
1214 			if (SHORT1FROMMP(mp1) & KC_CTRL)
1215 			    WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGERIGHT));
1216 			else
1217 			    WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINERIGHT));
1218 			break;
1219 		}
1220 	    }
1221 	    break;
1222 	default:
1223 	    /* All messages not handled by the ClientWndProc must be passed
1224 	     * along to the Presentation Manager for default processing
1225 	     */
1226 	    return WinDefWindowProc(hwnd, mess, mp1, mp2);
1227     }
1228     return (MRESULT) FALSE;
1229 }
1230 
1231 
1232 
1233 /* About Dialog Box */
1234 MRESULT EXPENTRY
AboutDlgProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)1235 AboutDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1236 {
1237     switch (msg) {
1238 	case WM_COMMAND:
1239 	    switch (COMMANDMSG(&msg)->cmd) {
1240 		case DID_OK:
1241 		    WinDismissDlg(hwnd, TRUE);
1242 		    return (MRESULT) TRUE;
1243 	    }
1244 	    break;
1245     }
1246     return WinDefDlgProc(hwnd, msg, mp1, mp2);
1247 }
1248