File:  [OS/2 SDKs] / pmsdk / samples / linefrac / linefrac.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:28:32 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: pmsdk-1989, HEAD
Microsoft OS/2 SDK PM 02-24-1989

/************************************************************************
*
*   linefrac.c -- Main window procedure for LineFractal window class.
*
*   Created by Microsoft Corporation, 1989
*
************************************************************************/

#define INCL_WIN
#define INCL_GPI
#define INCL_DOSSEMAPHORES
#define INCL_DOSMEMMGR
#define INCL_DOSPROCESS
#include <os2.h>
#include <mt\stdlib.h>

#define INCL_GLOBALS
#define INCL_THREADS
#include "linefrac.h"

#define INCL_LFMAIN
#define INCL_LFINIT
#define INCL_LFTHREAD
#define INCL_LFPS
#define INCL_LFCMD
#define INCL_LFDRAW
#include "lffuncs.h"




/************************************************************************
*
*   Global Variables
*
************************************************************************/

GLOBALDATA global;




/************************************************************************
*
*   main
*
*   WinInitialize resizes our ring 2 stack, among other things, so
*   we won't GP fault trying to do graphics.  WinCreateMsgQueue defines
*   us as a REAL PM app. (as does the WINDOWAPI in the .DEF file).
*   Call a subroutine to register our window class and create a window.
*   Loop over messages.  Exit cleanly.
*
************************************************************************/

VOID cdecl
main( VOID )
{
    QMSG qMsg;
    int iRet = 0;

    global.hab	 = WinInitialize(NULL);
    global.hMsgQ = WinCreateMsgQueue(global.hab, 0);

    if (LfInitApp())
	while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
	    WinDispatchMsg( global.hab, (PQMSG)&qMsg );
    else
	iRet = -1;

    WinDestroyWindow( global.hwndFrame );
    WinDestroyMsgQueue( global.hMsgQ );
    WinTerminate( global.hab );
    DosExit(EXIT_PROCESS, iRet);
}




/************************************************************************
*
*   LineFracWndProc
*
*   Process messages for the LineFractal window class.
*
************************************************************************/

ULONG CALLBACK
LineFracWndProc( hwnd, usMsg, mp1, mp2 )
HWND   hwnd;
USHORT usMsg;
MPARAM  mp1;
MPARAM  mp2;
{
    HPS     hps;
    USHORT  iNewTop;
    int     i;
    PTHR pthr;
    RECTL rcl;
    BOOL  fIsTimerUsed;

    switch (usMsg)
    {
    case WM_CREATE:
	if ((global.hptr)[global.usCurPtr])
	    WinSetPointer(HWND_DESKTOP,(global.hptr)[global.usCurPtr]);
	break;

    case WM_CLOSE:
	LfClose(hwnd);
	break;

    case WM_COMMAND:
	LfCommand(hwnd, LOUSHORT(mp1));
	break;

    case WM_TIMER:
	if (LOUSHORT(mp1) == IDT_AUTOSTARTREDRAW)
	{
	    fIsTimerUsed = FALSE;
	    for (i = 0; i < global.cThr; ++i)
		if (global.aThr[i]->fAutoStartRedraw)
		{
		    DosSemClear(&(global.aThr[i])->lSemRedraw);
		    fIsTimerUsed = TRUE;
		}
	    if (!fIsTimerUsed)
		LfStopRedrawTimer();
	    else
	    {
		LfStopRedrawTimer();
		LfStartRedrawTimer();
	    }
	}
	else if (LOUSHORT(mp1) == IDT_AUTOSWITCH)
	{
	    DosEnterCritSec();
	    iNewTop = (global.iThrTop + 1) % global.cThr;
	    DosExitCritSec();
	    LfBringThreadToTop(global.aThr[iNewTop]);
	}
	else
	    goto pass_it_on;
	break;

    case WM_ERASEBACKGROUND:
	LfEraseBackground(hwnd, NULL, NULL, NULL);
	return FALSE;
	break;

    case WM_PAINT:
	if (!global.pThrTop)
	    WinSendMsg(hwnd, WM_COMMAND, (MPARAM)IDM_DCMEMORY, 0);

	hps = WinBeginPaint(global.hwnd, NULL, &rcl);
	if (global.pThrTop)   /* only try to paint if we have a drawing */
	    LfPaint(hps, &rcl);
	WinEndPaint(hps);
	break;

    case WM_CHAR:
	if (LOUSHORT(mp1) & KC_CHAR)
	    LfChar(hwnd, (char)mp2);
	break;

    case WM_BUTTON1DOWN:
    case WM_BUTTON2DOWN:
	LfButtonDown(hwnd, mp1);
	WinSetFocus(HWND_DESKTOP, hwnd);
	break;

    case WM_BUTTON1UP:
    case WM_BUTTON2UP:
	LfButtonUp(usMsg);
	break;

    case WM_MOUSEMOVE:
	LfMouseMove();
	break;

    case WM_SIZE:
	/* Resize each PS that has fAutoSizePS set to TRUE. */

	WinQueryWindowRect(global.hwnd, &global.rcl);
	global.bm.cx = (USHORT) (global.rcl.xRight - global.rcl.xLeft);
	global.bm.cy = (USHORT) (global.rcl.yTop   - global.rcl.yBottom);

	for (i = 0; i < global.cThr; ++i)
	    if (pthr = global.aThr[i])
		if (pthr->hps)
		    if (pthr->fAutoSizePS)
		    {
			global.bm.cPlanes   = pthr->cPlanes;
			global.bm.cBitCount = pthr->cBitCount;

			if (LfResizePS(pthr))
			    DosSemClear(&pthr->lSemRedraw);
		    }

	/* fall through -- we might want to restart point accumulation,
	   but don't want to process the resize message */

    default:
pass_it_on:
	return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
	break;
    }

    return FALSE;
}




/************************************************************************
*
*   LfClose
*
*   Kill all the threads still running and delete all our fancy pointers.
*   In general, prepare to terminate the program.
*
************************************************************************/

VOID
LfClose(hwnd)
HWND hwnd;
{
    int i;

    WinSendMsg(hwnd, WM_COMMAND, (MPARAM)IDM_KILLALLTHREADS, 0);
    WinSetPointer(HWND_DESKTOP,
		  WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
    for (i = 0; i < NUM_PTR_SHAPES; ++i)
	if ((global.hptr)[i])
	    WinDestroyPointer((global.hptr)[i]);
    if (global.hptrTrack)
	WinDestroyPointer(global.hptrTrack);
    if (global.hptrPaste)
	WinDestroyPointer(global.hptrPaste);
    WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
}




/************************************************************************
*
*   LfEraseBackground
*
*   Erase the window background to a hatch pattern.  This enables the
*   user to see where the bitmap's edges are in case it's smaller
*   than the window.
*
************************************************************************/

VOID
LfEraseBackground(hwnd, hpsCaller, prclUpdate, prclX)
HWND hwnd;
HPS hpsCaller;
PRECTL prclUpdate;
PRECTL prclX;	/* excluded rectangle */
{
    HPS hps;
    RECTL rcl;
    RECTL rclT;
    AREABUNDLE ab;
    HRGN hrgnClipOld;
    HRGN hrgn;
    HRGN hrgnT;


    if (hpsCaller)
	hps = hpsCaller;
    else
	hps = WinGetPS(hwnd);

    if (prclUpdate)
	rcl = *prclUpdate;
    else
	WinQueryUpdateRect(hwnd, (PRECTL)&rcl);

    ab.lColor	  = CLR_BLACK;
    ab.lBackColor = CLR_WHITE;
    ab.usSymbol   = PATSYM_DIAG1;
    GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR|ABB_BACK_COLOR|ABB_SYMBOL,
		0L, (PBUNDLE)&ab);


    /* Make a region out of the nearest rectangle, then copy the real
     * region data into it.  Set this as our clip rectangle.
     */
    if ((hrgn = GpiCreateRegion(hps, 1L, &rcl)) != HRGN_ERROR)
    {
	WinQueryUpdateRegion(hwnd, hrgn);
	GpiSetClipRegion(hps, hrgn, &hrgnClipOld);
    }

    if (!prclX)
	GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rcl, ROP_PATCOPY, NULL);
    else
    {
	if (prclX->yTop < rcl.yTop)
	{
	    rclT.xLeft	 = rcl.xLeft;
	    rclT.yBottom = prclX->yBottom;
	    rclT.xRight  = rcl.xRight;
	    rclT.yTop	 = rcl.yTop;
	    GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
	}

	if (prclX->xRight < rcl.xRight)
	{
	    rclT.xLeft	 = prclX->xRight;
	    rclT.yBottom = rcl.yBottom;
	    rclT.xRight  = rcl.xRight;
	    rclT.yTop	 = prclX->yTop;
	    GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
	}
    }

    if (hrgnClipOld != HRGN_ERROR)
	GpiSetClipRegion(hps, hrgnClipOld, &hrgnT);
    if (hrgn != HRGN_ERROR)
	GpiDestroyRegion(hps, hrgn);

    if (!hpsCaller)
	WinReleasePS(hps);
}




/************************************************************************
*
*   LfPaint
*
*   If we have a bitmap, blt it to the screen, no matter what state
*   it's in.  If the selection rectangle is still alive, then display
*   it, too.  Note that it goes directly to the screen, so we have to
*   redraw it each time the bitmap is thrown back up.
*
************************************************************************/

VOID
LfPaint(hps, prcl)
HPS  hps;
PRECTL prcl;
{
    POINTL  aptl[4];

    if (global.pThrTop)
    {
	switch (global.pThrTop->dcType)
	{
	case IDM_DCDIRECT:	/* all drawing is already on the screen */
	    break;

	case IDM_DCPOSTSCRIPT:
	case IDM_DCPROPRINTER:
	    break;

	case IDM_DCMEMORY:

	    GpiSetAttrs(hps, PRIM_IMAGE, IBB_COLOR|IBB_BACK_COLOR, 0L, &global.pThrTop->ib);

	    aptl[0].x = 0L;
	    aptl[0].y = 0L;
	    aptl[1].x = (global.pThrTop->rcl).xRight;
	    aptl[1].y = (global.pThrTop->rcl).yTop;
	    aptl[2].x = 0L;
	    aptl[2].y = 0L;

	    GpiBitBlt(hps, global.pThrTop->hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
	    LfEraseBackground(global.hwnd, hps, prcl, &(global.pThrTop->rcl));
	    break;

	default:
	    break;
	}
	if (global.fShowSelectRc)
	    LfShowSelectRc(hps, global.fTempSelect ? &global.rclSelect : &global.rclCutCopy);
    }
}




/************************************************************************
*
*   LfShowSelectRc
*
*   Draw the selection rectangle in the given presentation space.  The
*   rectangle is drawn in xor-mode so this can be called to remove it
*   as well as show it.
*
************************************************************************/

VOID
LfShowSelectRc(hps, lprc)
HPS hps;
PRECTL lprc;
{
    LINEBUNDLE lb;


    lb.lColor	 = CLR_TRUE;
    lb.usMixMode = FM_XOR;
    lb.usType	 = LINETYPE_ALTERNATE;
    GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR|LBB_MIX_MODE|LBB_TYPE,
		0L, (PBUNDLE)&lb);
    GpiSetCurrentPosition(hps, (POINTL *)&(lprc->xLeft));
    GpiBox(hps, DRO_OUTLINE, (POINTL *)&(lprc->xRight), 0L, 0L);
}




/************************************************************************
*
*   LfChar
*
*   Handle LineFractal's keyboard interface.  This consists of:
*
*   <space>	Cancels the selection rectangle.
*   0-9 	Brings thread i to the top, if it exists.
*
************************************************************************/

VOID
LfChar(hwnd, ch)
HWND hwnd;
char ch;
{
    HPS hps;
    PRECTL lprc;
    int i;

    if (ch == ' ')
    {
	if (global.fShowSelectRc)
	{
	    global.fShowSelectRc = FALSE;
	    hps = WinGetPS(hwnd);
	    if (global.fTempSelect)
	    {
		lprc = &global.rclSelect;
		global.fTempSelect = FALSE;
	    }
	    else
		lprc = &global.rclCutCopy;
	    LfShowSelectRc(hps, lprc);
	    WinReleasePS(hps);
	}
    }
    else if (ch >= '0' && ch <= '9')
    {
	i = ch - '0';
	if (i < global.cThr)
	    LfBringThreadToTop(global.aThr[i]);
    }
}




/************************************************************************
*
*   LfMouseMove
*
*   Handle actions necessary upon each move of the mouse pointer.
*   This consists of resetting the mouse pointer -- if we pass
*   this on to WinDefWindowProc, it will reset it to the arrow.
*   As long as we're setting the pointer so often, we can do a
*   little animation.
*
************************************************************************/

VOID
LfMouseMove()
{
    /* Do this so that if in tracking mode, the correct pointer
       shape appears immediately. */
    if (global.fTracking || global.fSelecting)
    {
	if (global.hptrTrack)
	    WinSetPointer(HWND_DESKTOP,global.hptrTrack);
	return;
    }
    if (global.fPasting)
    {
	if (global.hptrPaste)
	    WinSetPointer(HWND_DESKTOP,global.hptrPaste);
	return;
    }
    if (global.pThrTop)
    {
	 if (global.pThrTop->fBusy)
	 {
	    if (global.hptrWait)
		WinSetPointer(HWND_DESKTOP,global.hptrWait);
	    return;
	 }
    }
    global.usPtrCounter = (global.usPtrCounter+1) % global.usPtrThreshold;
    if (global.usPtrCounter == 0)
    {
	global.usCurPtr += global.usPtrIncr;
	if (global.usCurPtr <= 0)
	    global.usCurPtr = 0;
	else
	    global.usCurPtr %= NUM_PTR_SHAPES;
	if ((global.usCurPtr == NUM_PTR_SHAPES - 1) ||
	    (global.usCurPtr == 0))
	    global.usPtrIncr *= -1;
    }
    if ((global.hptr)[global.usCurPtr])
	WinSetPointer(HWND_DESKTOP,(global.hptr)[global.usCurPtr]);
}




/************************************************************************
*
*   LfButtonUp
*
*   Handle up clicks of the mouse buttons.  This consists of:
*
*   left button up	increase the depth of recursion
*   right button up	decrease the depth of recursion
*
*			In both cases, clear the semaphore so the
*			drawing can restart at the new level of
*			recursion.
*
************************************************************************/

VOID
LfButtonUp(usMsg)
USHORT usMsg;
{
    if (global.fMouseChangesRecursion)
    {
	if (usMsg == WM_BUTTON1UP)
	    global.pThrTop->usRecursion = ++global.pThrTop->usRecursion;
	else if (global.pThrTop->usRecursion > 0)
	    global.pThrTop->usRecursion = --global.pThrTop->usRecursion;

	global.pThrTop->flMiscAttrs |= LFA_RECURSION;
	global.pThrTop->fUpdateAttrs = TRUE;
	global.fUpdateAttrs = TRUE;

	if (global.pThrTop->hps)
	{
	    global.pThrTop->fInterrupted = TRUE;
	    DosSemClear(&(global.pThrTop)->lSemRedraw);
	}
    }
}




/************************************************************************
*
*   LfButtonDown
*
*   Handle down clicks of the mouse buttons.  This consists of
*   changing the mouse pointer depending upon which mode we're in
*   and calling off to the subroutine to do the real work given
*   the position at which the mouse button was clicked.  The modes
*   are "tracking", "selecting", and "pasting".  Tracking means the
*   user is defining the new dimensions of the fractal.  Selecting
*   means the user is dragging a rectangle to cut or copy.  Pasting
*   means the user is positioning the cut or copied rectangle in
*   the window.
*
************************************************************************/

VOID
LfButtonDown(hwnd, mp1)
HWND hwnd;
MPARAM mp1;
{
    POINTS pt;

    if (global.fTracking)
    {
	if (global.hptrTrack)
	    WinSetPointer(HWND_DESKTOP,global.hptrTrack);
	pt.x = LOUSHORT(mp1);
	pt.y = HIUSHORT(mp1);
	LfSelectDimension(hwnd, pt);
	global.fTracking = FALSE;
	if ((global.hptr)[global.usCurPtr])
	    WinSetPointer(HWND_DESKTOP,(global.hptr)[global.usCurPtr]);
	if (global.pThrTop->fAttrRedraw)
	{
	    global.pThrTop->fInterrupted = TRUE;
	    DosSemClear(&(global.pThrTop)->lSemRedraw);
	}
    }
    else if (global.fSelecting)
    {
	if (global.hptrTrack)
	    WinSetPointer(HWND_DESKTOP,global.hptrTrack);
	pt.x = LOUSHORT(mp1);
	pt.y = HIUSHORT(mp1);
	LfSelect(hwnd, pt);
	global.fSelecting = FALSE;
	if ((global.hptr)[global.usCurPtr])
	    WinSetPointer(HWND_DESKTOP,(global.hptr)[global.usCurPtr]);
    }
    else if (global.fPasting)
    {
	if (global.hptrPaste)
	    WinSetPointer(HWND_DESKTOP,global.hptrPaste);
	pt.x = LOUSHORT(mp1);
	pt.y = HIUSHORT(mp1);
	LfPaste(hwnd);
	global.fPasting = FALSE;
	if ((global.hptr)[global.usCurPtr])
	    WinSetPointer(HWND_DESKTOP,(global.hptr)[global.usCurPtr]);
    }
}




/************************************************************************
*
*   LfStartRedrawTimer
*
************************************************************************/

VOID
LfStartRedrawTimer()
{
    USHORT timeout;

    if (!global.fTimerOn)
    {
	timeout = (USHORT) ((rand()/32767.0) *
		  (global.usMaxTimerDelay  - global.usMinTimerDelay) +
		   global.usMinTimerDelay);
	WinStartTimer(global.hab, global.hwnd, IDT_AUTOSTARTREDRAW, timeout);
	global.fTimerOn = TRUE;
    }
}




/************************************************************************
*
*   LfStopRedrawTimer
*
************************************************************************/

VOID
LfStopRedrawTimer()
{
    WinStopTimer(global.hab, global.hwnd, IDT_AUTOSTARTREDRAW);
    global.fTimerOn = FALSE;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.