User:Woozle/kscope

from HTYP, the free directory anyone can edit if they can prove to me that they're not a spambot
< User:Woozle
Revision as of 20:41, 23 January 2018 by Woozle (talk | contribs) (updated syntax highlight tags)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

kscope is a screensaver I wrote for Windows 3.11 using Visual C 1.5, but the compiled .exe works in Win95, Win98, and WinXP as well (though in WinXP I can't figure out how to add it to the list of available screensavers).

A screenshot and the compiled .exe are available here.

k3.hpp

/*
 FILE	: k3.hpp
 PURPOSE: header file for k3.cxx
 HISTORY:
	NWS	1994aug21 began adapting from BOUNCER.H
	NWS	1994aug26 adapting unfinished KALEI code to SCTR
	NWS	1995feb17 trying to figure out why kscope setup dialog won't load
	NWS	1995feb18 done; creating line_drawer object to eliminate DC & PEN conflicts
*/
                       
                       
#include <windows.h>
#include <scrnsave.h>
#include "resource.h"
#include "gtypes.h"
#include "wgraf.hpp"	/* wpix_rgb */
#include "k_math.hpp"
#define MEM_LARGE   
#define FAR_PTRS                    
#include "k_model.h"	/* fp_void */

void	GetIniEntries(void);
void	MoveImage(HWND hWnd);
void	GetIniSettings(void);
void	WriteProfileInt(LPSTR key, LPSTR tag, int i);
extern BOOL FAR PASCAL ScreenSaverConfigureDialog(HWND,UINT,WPARAM,LPARAM);

k3.cpp

/*
 FILE		: k3.cxx -- kaleidascope screen saver
 FUNCTIONS	:
	ScreenSaverProc()
	RegisterDialogClasses()
	ScreenSaverConfigureDialog()
 HISTORY	:
	NWS	1994aug21 began adapting from BOUNCER.C
	NWS	1994aug26 adapting unfinished KALEI code to SCTR
	NWS	1995feb17 migrating sctr back to kaleidascope (it _was_ working...)
*/
#include <assert.h>
#include <memory.h>
#include <math.h>

#define WIN_GRAFIX

#include "k3.hpp"

/* Global used by SCRNSAVE.LIB. Required for all screen savers. */
extern "C" char szAppName[40];
char szAppName[40];

/* Globals specific to this app. */
char szName[]			= "Kaleidascope";	/* used by scrnsav library (how?) */
char szSpeed[]			= "speed";
/* "kaleidascope" stuff */
char szSegs[]			= "#segs";
char szLinks[]			= "#links";
char szSoftInc[]		= "interval";
char szRandSeed[]		= "random seed";
char szClear[]			= "clear";
char szPenType[]		= "pen type";
char szMoveColors[]		= "move colors";
char szColorLinks[]		= "color links";
// window classes
char szTestWin[]		= "SSTestWin";

/* Externals defined in SCRNSAVE.LIB. Required for all screen savers. */
HINSTANCE	_cdecl hMainInstance;
HWND		_cdecl hMainWindow;
char		_cdecl szIsPassword[22];
char		_cdecl szIniFile[MAXFILELEN];
char		_cdecl szScreenSaver[22];
char		_cdecl szPassword[16];
char		_cdecl szDifferentPW[BUFFLEN];
char		_cdecl szChangePW[30];
char		_cdecl szBadOldPW[BUFFLEN];
char		_cdecl szHelpFile[MAXFILELEN];
char		_cdecl szNoHelpMemory[BUFFLEN];
UINT		_cdecl MyHelpMessage;
HOOKPROC	_cdecl fpMessageFilter;

WORD wTimer;				// timer id

/* enumerated types used in storage */

enum win_pen_type {		/* Windows API pen type */
	wpen_solid,
	wpen_dash,
	wpen_dot,
	wpen_dashdot,
	wpen_dashdotdot,
	wpen_null,
	wpen_insideframe
};
	
enum ks_pen_type {		/* kscope pen type */
	kpen_solid,
	kpen_dash,
	kpen_dot,
	kpen_dashdot,
	kpen_dashdotdot,
	kpen_dithered,
	kpen_callback,
	kpen_software
};

const ks_pen_type highest_api_kpen = kpen_dithered;

/* universal SETUP options */
WORD nSpeed = 10;
flag bPassword;
/* "kaleidascope" options */
WORD		nSegs		= 1;
WORD		nLinks		= 200;
ks_pen_type	nPenType	= kpen_software;
WORD		nSoftInc	= 24;
WORD		nRandSeed	= 0;
flag		bClearScrn	= Yes;
flag		bMoveColors	= No;
flag		bColorLinks	= No;

/* common vars & objects */
	/* Windows stuff */
gbox	scr_box;
int		scr_bits;	/* screen bits per pixel */
flag	scr_pltt;	/* screen supports palettes? */
	/* other variables */
flag		active = No;
gpt			start_pt;

/* "kaleidascope" vars & objects */
win_pen_type	aPenType;			/* actual Windows pen type */
byte			penWidth;			/* pen width to use */
flag			softPen;			/* not using an hPen */

	/* Windows stuff */
HINSTANCE	hInst;		/* handle to app instance */
HWND		hMsg;		/* handle to window for timer messages */
HWND		hDlg = 0;	/* handle to configuration dialog, if active */
HWND		hPenList;
HWND		hSoftInc;
HWND		hLineDemo;	/* handle to line-demo window */

	/* other variables */
flag		drawing;
flag		is_saver = Yes;
gpt			new_pt[3];	
WORD		link,seg;
WORD		topSegPoint;	/* top point in seg array */
WORD		topSegLink;		/* top seg for drawing links */
wpix_rgb	cur_color;
gloc		dot_count;

	/* major objects */
struct seg_def {
	wpix_rgb	color;
	gpt			point;
};
typedef seg_def asegs[];
asegs*	axes;				// pointer to axis array

struct line_drawer : public gbox {
/*====DATA====*/
	HDC				hDC;		/* handle to device context for drawing */
	HPEN			hPen;		/* current drawing pen, if any */
/*====CODE====*/
	void PenPrep(flag);
	void GetColor(COLORREF icolor);
	void DoLine();
	void CALLBACK LineMethod(int X, int Y);
};
typedef line_drawer* p_line_drawer;

HWND		hWnd;			/* handle to window for drawing lines */
//HDC			call_hDC;		/* FUTURE: thunk the line callback */
/* also make cur_color a member */
line_drawer	global_line;	/* global line-drawer for actual kaleidascope */

typedef void	(CALLBACK line_drawer::* LinMeth)(int,int,LPARAM);	/* LinMeth: LineDDAProc() */
//struct kprocs {
//	union {
//		uprocs	up;
//		LinMeth	lm;
//	};
//};

//class ckprocs : public kprocs {
//	ckprocs() : kprocs()	{}
//	ckprocs(LinMeth ilm)	{ lm = ilm; }
//};
/*==============================================================*\
 FUNCTION	: LineCallback(int,int,proc)
 MODEL		: LineDDAProc()
\*==============================================================*/
void CALLBACK LineCallback(int X, int Y, LPARAM pclass)
{
	((p_line_drawer)pclass) -> LineMethod(X,Y);
}

			/*===================================*\
			 CLASS	: line_drawer
			 PURPOSE: drawing of styled lines
			\*===================================*/
/*==============================================================*\
 FUNCTION	: line_drawer::PenPrep(yes/no)
 GLOBALS	:
	nPenType	--> selected pen type from list
	aPenType	<-- actual Win HPEN to use, if any
	softPen		<-- Yes = drawing will be done without an HPEN
 MEMBERS	:
 	fpCall		<-- pointer to instance of callback function
	hPen		<-- (cleared) handle to pen, if any
\*==============================================================*/
void line_drawer::PenPrep(flag ienter)
{
	if (ienter) {
//		fpCall = 0;
//		fpMeth = 0;
		switch (nPenType) {
			case kpen_callback: {
//				FARPROC fpMeth = MakeProcInstance((FARPROC)LineCallback,hInst);
// old #1
//				fpCall = MakeThunk(this,fpMeth);
//				fpCall = line_thunk.MakeThunk(this,ckprocs(LineCallback).up);
// old #2
//				fpCall = line_thunk.MakeThunk(this,ckprocs(LineCallback).up); /*TEST*/
// old #3
//				fpMeth = MakeProcInstance(ckprocs(LineCallback).up.fp, hInst);
//				fpCall = line_thunk.MakeThunk(this,cprocs(fpMeth));
				/* no break -- also do kpen_software processing */
			}
			case kpen_software:
				softPen = Yes;
				aPenType = wpen_null;	/* just for clarity */
				break;
			case kpen_dithered:
				softPen = No;
				aPenType = wpen_insideframe;
				penWidth = 2;
				break;
			default:
				softPen = No;
				aPenType = (win_pen_type)nPenType;
				penWidth = 0;
		}
		hPen = 0;
//		hPenOld = 0;
	} else {
#ifdef x1995feb18 /* PROBABLY UNNECESSARY */
		if (hPen) {
			HPEN hPenOld = SelectObject(hDC, GetStockObject(NULL_PEN));	/* deselect last pen */
			DeleteObject(hPenOld);					/* destroy the last created pen */
		}
#endif
//		line_thunk.FreeThunk();
//		if (fpMeth)
//			FreeProcInstance(fpMeth);
	}
}
/*==============================================================*\
 FUNCTION	: line_drawer::GetColor()
\*==============================================================*/
void line_drawer::GetColor(COLORREF icolor)
{
	cur_color.wc = icolor;
	if (!softPen) {
		SetBkColor(hDC,RGB(0,0,0));
		
		hPen = CreatePen(aPenType,penWidth,cur_color.wc);
		HPEN hPenOld = SelectObject(hDC,hPen);
		DeleteObject(hPenOld);					/* kill the old pen */
	}
}
/*==============================================================*\
 FUNCTION	: line_drawer::DoLine
 ACTION		: draw a single line
 GLOBALS	:
 	nPenType	--> selected type of drawing to do
 MEMBERS	:
	(gbox)		--> endpoints of line to draw
\*==============================================================*/
void line_drawer::DoLine()
{
	switch (nPenType) {
		case kpen_callback:
			dot_count = 0;
//			call_hDC = hDC;		/* TO BE ELIMINATED LATER */
//			LineDDA(A.X, A.Y, B.X, B.Y, fpCall, this);
			LineDDA(A.X, A.Y, B.X, B.Y, (FARPROC)LineCallback, (LPARAM)(fp_void)this);
			break;
		case kpen_software: {
			float xdiff = X.Diff();
			float ydiff = Y.Diff();
//			float xydiff = (float)fabs(xdiff) + (float)fabs(ydiff);		/* same as callback */
			float xydiff = (float)sqrt((xdiff*xdiff) + (ydiff*ydiff));
			if (xydiff) {
				float xinc = xdiff/xydiff * nSoftInc;
				float yinc = ydiff/xydiff * nSoftInc;
				float xloc = X.A;
				float yloc = Y.A;
				int idx, count = (int)(xydiff/nSoftInc)+1;
				for (idx=count; idx--; idx>0) {
					SetPixel(hDC,(gloc)xloc,(gloc)yloc,cur_color.wc);
					xloc += xinc;
					yloc += yinc;
				};
			}
			break;
		}
		default:
			SetBkMode(hDC,TRANSPARENT);
			MoveTo(hDC, A.X, A.Y);
			LineTo(hDC, B.X, B.Y);
	}
}
/*==============================================================*\
 FUNCTION	: line_drawer::LineMethod(int,int)
 USAGE		: called by ::LineCallback(int,int,LPRARM)
\*==============================================================*/
void CALLBACK line_drawer::LineMethod(int X, int Y)
{
	if (!dot_count) {
		dot_count = nSoftInc;
#ifdef _DBG
		COLORREF acol = SetPixel(hDC,X,Y,cur_color.wc);
#else		
		SetPixel(hDC,X,Y,cur_color.wc);
#endif
	} else
		dot_count--;
}

			/*===================================*\
			 SECTION: normal functions
			\*===================================*/
/*==============================================================*\
 FUNCTION	: RegisterDialogClasses
 PURPOSE	: Entry point for registering window classes
	required by configuration dialog box.
 INPUT		: hWnd -- Handle to window
 RETURNS	: nothing
\*==============================================================*/
BOOL RegisterDialogClasses(HINSTANCE ihInst)
{
	WNDCLASS wc;

	hInst = ihInst;

	wc.style			= 0x0;								// Class style(s) (none)
	wc.lpfnWndProc		= ScreenSaverProc;					// Message handler function
	wc.cbClsExtra		= 0;								// No per-class extra data.
	wc.cbWndExtra		= 0;								// No per-window extra data.
	wc.hInstance		= hInst;							// App that owns the class.
	wc.hIcon			= LoadIcon(hInst,"ID_MAINICON");	// icon to use
	wc.hCursor			= 0;
	wc.hbrBackground	= 0;								// window must paint background
	wc.lpszMenuName		= 0;								// Name of menu resource in .RC file.
	wc.lpszClassName	= szTestWin;						// Name used in call to CreateWindow.

	if (!RegisterClass(&wc))						// register the class
		return No;										// didn't work
	return Yes;
}
/*==============================================================*\
 FUNCTIONS	: SetSettings
 ACTION		: copy the settings from the dialog box to the
	program variables
\*==============================================================*/
void SetSettings()
{
	if (hDlg) {
		nSpeed		= GetDlgItemInt(hDlg, IDC_SPEED,NULL, No);
		nSegs		= GetDlgItemInt(hDlg, IDC_NUM_SEGS,NULL, No);
		nLinks		= GetDlgItemInt(hDlg, IDC_NUM_LINKS,NULL, No);
		nSoftInc	= GetDlgItemInt(hDlg, IDC_INTERVAL,NULL, No);
		nPenType	= (ks_pen_type)SendMessage(hPenList,CB_GETCURSEL,0,0);
	/* nb don't set random seed from dialog */
		bClearScrn	= IsDlgButtonChecked(hDlg, IDC_CLEAR_SCRN);
		bColorLinks	= IsDlgButtonChecked(hDlg, IDC_COLOR_LINKS);
		bMoveColors	= IsDlgButtonChecked(hDlg, IDC_MOVE_COLORS);
		bPassword	= IsDlgButtonChecked(hDlg, ID_PASSWORDPROTECTED);
	}

	WriteProfileInt(szAppName, szSpeed,		nSpeed);
	WriteProfileInt(szAppName, szSegs,		nSegs);
	WriteProfileInt(szAppName, szLinks,		nLinks);
	WriteProfileInt(szAppName, szSoftInc,	nSoftInc);
	WriteProfileInt(szAppName, szPenType,	nPenType);
	WriteProfileInt(szAppName, szRandSeed,	nRandSeed);
	WriteProfileInt(szAppName, szClear,		bClearScrn);
	WriteProfileInt(szAppName, szColorLinks,bColorLinks);
	WriteProfileInt(szAppName, szMoveColors,bMoveColors);
	WriteProfileInt(szAppName, szIsPassword,bPassword);
}
/*==============================================================*\
 FUNCTION	: Prepare(yes/no)
 ACTION		: start or finish screen saver (e.g. allocate or
	deallocate memory, etc.)
\*==============================================================*/
void Prepare(flag ienter)
{
	if (ienter) {
		p_void mp;
		size_t ms;

		topSegPoint = nSegs + 2;				/* top point # in segment array */
		topSegLink = nSegs + 0;					/* top segment # for drawing links */
		ms = (topSegPoint+1) * sizeof(seg_def);	/* figure # of bytes to allocate */
		mp = malloc(ms);						/* allocate them */
		axes = (asegs*)mp;						/* recast to segment array */
		memset(mp,0,ms);						/* clear the array */
		if (bMoveColors) {						/* if colors are persistent...*/
			seg = nSegs;
			while (seg > 0) {
				seg--;
				(*axes)[seg].color.SetRand();
			};
		}
		wTimer = SetTimer(hMsg, ID_TIMER, 0, NULL);
		if (!wTimer) {
			MessageBox(0,"Couldn't create timer","Error",MB_ICONEXCLAMATION);
			return;
		}
		GetClientRect(hWnd, &scr_box.wr);			/* get window size */
		global_line.hDC = GetDC(hWnd);				/* get window device context */

		link = 0;				/* go into loop first time */
		seg = topSegLink;		/* go into loop first time */

		srand(nRandSeed);
	} else {
		free(axes);
	/* Destroy any objects we created */
		if (wTimer)
			KillTimer(hMsg, ID_TIMER);
		if (global_line.hDC)
			ReleaseDC(hWnd, global_line.hDC);
		nRandSeed = rand();
		SetSettings();			/* save new random seed */
		if (hDlg)
			SetDlgItemInt(hDlg,IDC_RAND_SEED,nRandSeed,No);
	}
	global_line.PenPrep(ienter);
	active = ienter;
	drawing = No;
}
/*==============================================================*\
 FUNCTION	: DoLink
 ACTION		: draw a line with appropriate reflections
\*==============================================================*/
void DoLink(gbox end_pt)
{
	gpt		scr_ctr	= scr_box.Mid();
	
	global_line.A = end_pt.A;
	global_line.B = end_pt.B;

	global_line.DoLine();	/* X norm, Y norm */
	global_line.X.Reflect(scr_ctr.X);
	global_line.DoLine();	/* X refl, Y norm */
	global_line.Y.Reflect(scr_ctr.Y);
	global_line.DoLine();	/* X refl, Y refl */
	global_line.X.Reflect(scr_ctr.X);
	global_line.DoLine();	/* X norm, Y refl */
}
/*==============================================================*\
 FUNCTION	: MoveImage
 ACTION		: Move image around the screen
 INPUT		: hWnd -- Handle to window
 RETURNS	: nothing
\*==============================================================*/
static void MoveImage() 
{
	wpix_rgb	color1, color2;	/* for color interpolation if (bColorLinks) */
	if (active) {
		for (word idx = 0; idx < nSpeed; idx++) {
loop:		if (!bMoveColors && (seg==0)) {
				seg = topSegLink;
			} else {
				seg++;
				if (seg > topSegLink) {
					if (link == 0) {
						link = nLinks;

/* shift points up the array one notch */
						if (bMoveColors) {
							for (seg=topSegPoint; seg>0; seg--) {
								(*axes)[seg].point = (*axes)[seg-1].point;
							}
						} else {
							for (seg=topSegPoint; seg>0; seg--) {
								(*axes)[seg] = (*axes)[seg-1];
							}
							(*axes)[0].color.SetRand();
						}
						gpt old_pt = (*axes)[0].point;
						gpt new_pt;
						do {
							new_pt = scr_box.Random();
						} while (old_pt.xy == new_pt.xy);
						(*axes)[0].point = new_pt;
					} else
						link--;
					seg = 0;
				}
			}

/* figure current point triplet */
			for (int jdx = 2; jdx >= 0; jdx--) {
				new_pt[jdx] = (*axes)[seg+jdx].point;
			}
			
			if (seg == topSegLink) {
				color1.wc = 0;
				color2.wc = 0;
			} else {
				color1 = (*axes)[seg].color;
				color2 = (*axes)[seg+1].color;
            }
			if (!bColorLinks) {
				global_line.GetColor(color1.wc);
			}

			gbox link_line;
			gbox interbox;
			if (new_pt[0].xy && (new_pt[1].xy || !link)) {
				if (new_pt[1].xy && (new_pt[2].xy || !link)) {

					float portion = (float)link / (nLinks+1);

					interbox.A = new_pt[0];
					interbox.B = new_pt[1];
					link_line.A = interbox.Interp(portion);
	
					interbox.A = new_pt[1];
					interbox.B = new_pt[2];
					link_line.B = interbox.Interp(portion);

					if (bColorLinks) {
						if (seg == topSegLink) {
							global_line.GetColor(0);
						} else {
							global_line.GetColor(color1.Interp(portion,color2.wc));
							drawing = Yes;
						}
					} else if (cur_color.wc)
						drawing = Yes;
					if (drawing)
    					DoLink(link_line);
				}
			}
			if (!drawing)		/* do all non-visible processing immediately */
				goto loop;
		}
	}
}
/*==============================================================*\
 FUNCTION	: AboutBoxProc()
 ACTION		: handles About box
\*==============================================================*/
LONG FAR PASCAL AboutBoxProc(HWND ihWnd, UINT msg, WPARAM wd, LPARAM ld)
{
	switch (msg) {
		case WM_INITDIALOG:
			hWnd = GetDlgItem(ihWnd,IDC_TESTWIN);
			hMsg = ihWnd;
			Prepare(Yes);
			return Yes;
		case WM_TIMER:
			MoveImage();
            return 0;
		case WM_COMMAND:
			switch (wd) {
				case IDOK:
					EndDialog(ihWnd,0);
					return Yes;
			}
		case WM_DESTROY:
			Prepare(No);
			return 0;
	}
	return 0;
}
/*==============================================================*\
 FUNCTION	: GetScreenParams
 ACTION		: get information about the screen device
\*==============================================================*/
void GetScreenParams(HWND ihWnd)
{
	HDC scrn_hDC = GetDC(ihWnd);
	scr_pltt = (GetDeviceCaps(scrn_hDC,RASTERCAPS) & RC_PALETTE) != 0;
	scr_bits = GetDeviceCaps(scrn_hDC,BITSPIXEL);
	ReleaseDC(ihWnd,scrn_hDC);
}
/*==============================================================*\
 FUNCTION	: DoLineTest()
 ACTION		: demonstrate the selected pen type at various angles
\*==============================================================*/
void DoLineTest()
{
	PAINTSTRUCT far ps;
	HDC hDemoDC = BeginPaint(hLineDemo,&ps);
	assert(hDemoDC);

	gbox		demo_box;
	line_drawer local_line;

	local_line.hDC = hDemoDC;	/* set line's DC to line demo area */
	local_line.PenPrep(Yes);
	local_line.GetColor(RGB(0x0ff, 0x0ff, 0x0ff));

	GetClientRect(hLineDemo, &demo_box.wr);		/* get window size */
	FillRect(hDemoDC,&demo_box.wr,(HBRUSH)GetStockObject(BLACK_BRUSH));

	gloc line_siz;
	if (demo_box.X.Size() < demo_box.Y.Size())
		line_siz = demo_box.X.Size();
	else
		line_siz = demo_box.Y.Size();

	line_siz /= 2;
	local_line.A = demo_box.Mid();

	float idx_dec = ((float)_PI) * 0.05f;
	for (float idx = (float)_PI * 2.0f; idx > 0.0; idx-=idx_dec) {
		local_line.Y.FitB((gloc)(sin(idx) * (float)line_siz));
		local_line.X.FitB((gloc)(cos(idx) * (float)line_siz));
		local_line.DoLine();
	}
	
//	ValidateRect(hLineDemo,0);	/* don't repaint over line demo */

	local_line.PenPrep(No);
	EndPaint(hDlg,&ps);			// finished with painting
}
/*==============================================================*\
 FUNCTION	: ScreenSaverConfigureDialog
 MODEL		: DialogProc()
 PURPOSE	: Dialog box function for configuration dialog.
 INPUT		: hWnd -- Handle to window
 RETURNS	: nothing
\*==============================================================*/
BOOL FAR PASCAL __export ScreenSaverConfigureDialog(HWND ihDlg, UINT msg, WPARAM wd, LPARAM ld)
{
	static	HWND hIDOK;
	static	HWND hSetPassword;
			HWND hTest;

	switch (msg) {
		case WM_INITDIALOG:
			hDlg = ihDlg;
		
			hPenList = GetDlgItem(hDlg,IDC_PEN_TYPE);	/* get handle for pen-type list */
			hSoftInc = GetDlgItem(hDlg,IDC_INTERVAL);
			hLineDemo = GetDlgItem(hDlg,IDC_LINE_TEST);	/* get line-demo control */

			GetIniEntries();
			GetIniSettings();
			SetDlgItemInt		(hDlg,IDC_SPEED,nSpeed,No);
			SetDlgItemInt		(hDlg,IDC_NUM_SEGS,nSegs,No);
			SetDlgItemInt		(hDlg,IDC_NUM_LINKS,nLinks,No); 
			SetDlgItemInt		(hDlg,IDC_RAND_SEED,nRandSeed,No);
			SetDlgItemInt		(hDlg,IDC_INTERVAL,nSoftInc,No);

			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Solid");
			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Dash");
			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Dot");
			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Dash-dot");
			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Dash-dot-dot");
			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Dithered");
			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Callback");
			SendMessage(hPenList,CB_ADDSTRING,0,(LPARAM)(char far*)"Software");
			SendMessage(hPenList,CB_SETCURSEL,nPenType,0);
			
			CheckDlgButton		(hDlg,IDC_CLEAR_SCRN,bClearScrn);
			CheckDlgButton		(hDlg,IDC_COLOR_LINKS,bColorLinks);
			CheckDlgButton		(hDlg,IDC_MOVE_COLORS,bMoveColors);

			SendDlgItemMessage	(hDlg,ID_PASSWORDPROTECTED,	BM_SETCHECK, bPassword, NULL);
			hSetPassword = GetDlgItem(hDlg, ID_SETPASSWORD);
			EnableWindow(hSetPassword, bPassword);

			hIDOK = GetDlgItem(hDlg, IDOK);

			return TRUE;
		case WM_DESTROY:
			hDlg = 0;
			return FALSE;
		case WM_PAINT: {
			if (nPenType > highest_api_kpen) {
				ShowWindow(hSoftInc,SW_SHOW);
			} else {
				ShowWindow(hSoftInc,SW_HIDE);
			}
			DoLineTest();
			return No;
		}
		case WM_COMMAND:
			switch (wd) {
				case IDOK:
					SetSettings();
					EndDialog(hDlg, TRUE);
					return TRUE;

				case IDCANCEL:
					EndDialog(hDlg, FALSE);
					return TRUE;

				case ID_TEST:
					is_saver = No;
					SetSettings();			/* save current settings to ini file */
					hTest = CreateWindow(
						szTestWin,
						"Kaleidascope",
						WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX |
							WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED,
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						hDlg,0,hInst,0);
					ShowWindow(hTest,SW_SHOWNA);
					return TRUE;

				case ID_ABOUT: {
					FARPROC fpDialog;
					fpDialog = MakeProcInstance((FARPROC)AboutBoxProc,hInst);
					SetSettings();
					DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUTBOX),hDlg,fpDialog);
					FreeProcInstance(fpDialog);
					break;
				}
				case ID_SETPASSWORD: {
					FARPROC fpDialog;
					fpDialog = MakeProcInstance((FARPROC)DlgChangePassword,hMainInstance);
					if(!fpDialog)
						return FALSE;
					DialogBox(hMainInstance, MAKEINTRESOURCE(DLG_CHANGEPASSWORD), hDlg, fpDialog);
					FreeProcInstance(fpDialog);
					SendMessage(hDlg, WM_NEXTDLGCTL, hIDOK, 1l);
					break;
				}
				case ID_PASSWORDPROTECTED:
					bPassword ^= 1;
					CheckDlgButton(hDlg, wd, bPassword);
					EnableWindow(hSetPassword, bPassword);
					break;
				case IDC_PEN_TYPE: {
					if ((ld & 0x00080000) && !(ld & 0x00010000)) {
						ks_pen_type oldPenType = nPenType;
						nPenType = (ks_pen_type)SendMessage(hPenList,CB_GETCURSEL,0,0);
//						if (nPenType != oldPenType) {
							if (nPenType > highest_api_kpen)
								ShowWindow(hSoftInc,SW_SHOW);
							else
								ShowWindow(hSoftInc,SW_HIDE);
							InvalidateRect(hLineDemo,0,No);
							DoLineTest();
//						}
					}
				} break;
				case IDC_RAND_SEED:
					nRandSeed = GetDlgItemInt(hDlg, IDC_RAND_SEED,NULL, No);
					break;
			}
			break;
	}
	return FALSE;
}
/*==============================================================*\
 FUNCTION	: GetIniSettings
 ACTION		: Get initial settings from WIN.INI
 INPUT		: hWnd -- Handle to window
 RETURNS	: nothing
\*==============================================================*/
static void GetIniSettings()
{
	nSpeed		= GetPrivateProfileInt(szAppName, szSpeed,		nSpeed,		szIniFile);
	nSegs		= GetPrivateProfileInt(szAppName, szSegs,		nSegs,		szIniFile);
	nLinks		= GetPrivateProfileInt(szAppName, szLinks,		nLinks,		szIniFile);
	nSoftInc	= GetPrivateProfileInt(szAppName, szSoftInc,	nSoftInc,	szIniFile);
	nRandSeed	= GetPrivateProfileInt(szAppName, szRandSeed,	nRandSeed,	szIniFile);
	nPenType	= 
		(ks_pen_type)GetPrivateProfileInt(szAppName, szPenType,	nPenType,	szIniFile);
	bClearScrn	= GetPrivateProfileInt(szAppName, szClear,		bClearScrn,	szIniFile);
	bColorLinks	= GetPrivateProfileInt(szAppName, szColorLinks,	bColorLinks,szIniFile);
	bMoveColors	= GetPrivateProfileInt(szAppName, szMoveColors,	bMoveColors,szIniFile);
	bPassword	= GetPrivateProfileInt(szAppName, szIsPassword, FALSE,		szIniFile);
}
/*==============================================================*\
 FUNCTION	: ScreenSaverProc
 PURPOSE	: Main entry point for screen saver messages.
 USAGE		: This function is required for all screen savers.
 RETURNS	: depends on input message
\*==============================================================*/
LONG FAR PASCAL __export ScreenSaverProc(HWND ihWnd, UINT msg, WPARAM wd, LPARAM ld)
{
	hWnd = ihWnd;
	hMsg = ihWnd;
	switch (msg) {
		case WM_CREATE:
			GetScreenParams(ihWnd);
			if (scr_bits > 8)		/* if hiColor display...*/
				bColorLinks = Yes;		/* default is "move colors" = on */
			GetIniEntries();		/* Load the strings from the STRINGTABLE */
			GetIniSettings();		/* Load the initial bounce settings. */
			Prepare(Yes);
			GetScreenParams(hWnd);
			break;
		case WM_DESTROY:
			active = No;
			Prepare(No);
			break;
		case WM_ERASEBKGND:
			if (bClearScrn) {
				FillRect((HDC)wd,&scr_box.wr,(HBRUSH)GetStockObject(BLACK_BRUSH));
			}
			active = Yes;
			return 0L;
		case WM_TIMER:
			MoveImage();
            break;
		case WM_SIZE:
			GetClientRect(ihWnd, &scr_box.wr);			/* get window size */
			ReleaseDC(ihWnd,global_line.hDC);			/* release old device context */
			global_line.hDC = GetDC(ihWnd);				/* get new device context */
			if (bClearScrn) {
				FillRect(global_line.hDC,&scr_box.wr,(HBRUSH)GetStockObject(BLACK_BRUSH));
			}
			break;
		case WM_SYSCOMMAND:
			if (wd == SC_SCREENSAVE)
				is_saver = Yes;
			break;
	}
	if (is_saver)
		return DefScreenSaverProc(ihWnd,msg,wd,ld);
	else
		return DefWindowProc(ihWnd,msg,wd,ld);
}
/*==============================================================*\
 FUNCTION	: WriteProfileInt
 ACTION		: Write an unsigned integer value to CONTROL.INI.
 INPUT		:
 	name	- szSection - [section] name in .INI file
	szKey	- key= in .INI file
	i		- value for key above
 RETURNS	: nothing
\*==============================================================*/
static void WriteProfileInt(LPSTR szSection, LPSTR szKey, int i) 
{
	char achBuf[40];

    /* write out as unsigned because GetPrivateProfileInt() can't
     * cope with signed values!
     */
	wsprintf(achBuf, "%u", i);
	WritePrivateProfileString(szSection, szKey, achBuf, szIniFile);
}
/*==============================================================*\
 FUNCTION	: GetIniEntries()
\*==============================================================*/
void GetIniEntries(void)
{
  //Load Common Strings from stringtable...
	LoadString(hMainInstance, idsIsPassword, szIsPassword, 22);
	LoadString(hMainInstance, idsIniFile, szIniFile, MAXFILELEN);
	LoadString(hMainInstance, idsScreenSaver, szScreenSaver, 22);
	LoadString(hMainInstance, idsPassword, szPassword, 16);
	LoadString(hMainInstance, idsDifferentPW, szDifferentPW, BUFFLEN);
	LoadString(hMainInstance, idsChangePW, szChangePW, 30);
	LoadString(hMainInstance, idsBadOldPW, szBadOldPW, 255);
	LoadString(hMainInstance, idsHelpFile, szHelpFile, MAXFILELEN);
	LoadString(hMainInstance, idsNoHelpMemory, szNoHelpMemory, BUFFLEN);
}