/* Enhanced NCSA Mosaic from Spyglass "Guitar" Copyright 1994 Spyglass, Inc. All Rights Reserved Author(s): Jeff Hostetler jeff@spyglass.com Jim Seidman jim@spyglass.com */ /* w32wait.c -- code to manage WaitState while we're busy. */ #include "all.h" #ifdef FEATURE_IAPI #include "w32dde.h" #endif static int gPushCount = 0; static int bWaitLock = FALSE; // TRUE if we're disallowing updates void WAIT_SetStopButton(struct Mwin * tw, HWND hWndStop) { if (!tw) return; tw->hWndStop = hWndStop; return; } static unsigned long x_ScaleTerm(struct AsyncWaitInfo * awi, unsigned long x) { if (!awi) return 0; XX_DMsg(DBG_WAIT, ("x_ScaleTerm: nThermStart=%d nThermEnd=%d x=%d nScalingDenominator=%d\n", awi->nThermStart, awi->nThermEnd, x, awi->nScalingDenominator)); return ( awi->nThermStart + ( (awi->nThermEnd - awi->nThermStart) * x / awi->nScalingDenominator)); } static void x_SetRange(struct Mwin * tw, int nThermStart, int nThermEnd, int nScalingDenominator) { struct AsyncWaitInfo * awi; struct AsyncWaitInfo * awiPrev; /* we allow caller to define a range within our thermometer (0 to 25%, for example) and a scaling term (nr of iterations thru loop, for example). subsequent calls to ComeUpForAir will be scaled into this range. */ XX_DMsg(DBG_WAIT, ("WAIT_SetRange: %d %d %d\n", nThermStart, nThermEnd, nScalingDenominator)); if (!tw || !tw->awi) return; awi = tw->awi; awiPrev = awi->prev; awi->nThermStart = nThermStart; if (awi->nThermStart < 0) awi->nThermStart = 0; else if (awi->nThermStart > 99) awi->nThermStart = 99; if (awiPrev) awi->nThermStart = x_ScaleTerm(awiPrev,awi->nThermStart); awi->nThermEnd = nThermEnd; if ( (awi->nThermEnd < awi->nThermStart) || (awi->nThermEnd > 100)) awi->nThermEnd = 100; #if 0 /* I removed this. EWS */ if (awiPrev) awi->nThermEnd = x_ScaleTerm(awiPrev,awi->nThermEnd); #endif awi->nScalingDenominator = nScalingDenominator; if (awi->nScalingDenominator == 0) awi->nScalingDenominator = 1; awi->nLastScalingNumerator = 0; XX_DMsg(DBG_WAIT, ("nThermEnd=%d awi->nThermEnd=%d\n", nThermEnd, awi->nThermEnd)); return; } void WAIT_SetRange(struct Mwin * tw, int nThermStart, int nThermEnd, int nScalingDenominator) { if (!tw || !tw->awi) return; x_SetRange(tw,nThermStart,nThermEnd,nScalingDenominator); UpdateThermometer(tw,x_ScaleTerm(tw->awi,tw->awi->nLastScalingNumerator)); return; } static void x_fixup_status(struct Mwin * tw) { if (!tw || !tw->awi) { /* turn off stuff */ UpdateThermometer(tw,-1); BHBar_Update(tw); if (tw->hWndStop) TW_EnableButton(tw->hWndStop, FALSE); TBar_SetGlobe(tw,FALSE); } else { /* turn on stuff */ UpdateThermometer(tw,x_ScaleTerm(tw->awi,tw->awi->nLastScalingNumerator)); if (tw->awi->ewt < waitNoInteract) { BHBar_Update(tw); } else { /* If we've gone into a non-interaction state, the previous transient message must be invalid */ BHBar_SetStatusField(tw, ""); } if (tw->hWndStop) TW_EnableButton(tw->hWndStop, TRUE); TBar_SetGlobe(tw,TRUE); } return; } void WAIT_Push(struct Mwin * tw, enum WaitType ewt, unsigned char * szMessage) { struct AsyncWaitInfo * awi; #if 1 /* TODO fix me */ if (!tw) { XX_DMsg(DBG_WAIT, ("WAIT_Push: no tw\n")); return; } #endif XX_DMsg(DBG_WAIT, ("WAIT_Push: '%s' (type %d)\n", szMessage, ewt)); /* If progress app has been specified in the tw structure, use DDE */ #ifdef FEATURE_IAPI if (tw->szProgressApp[0] && (gPushCount == 0)) { DDE_Issue_BeginProgress(tw->szProgressApp, szMessage); DDE_Issue_SetProgressRange(tw->szProgressApp, 100); } #endif gPushCount++; awi = GTR_CALLOC(1,sizeof(struct AsyncWaitInfo)); if (!awi) return; /* if message given, use it. otherwise, use previous stack frames's message. */ if (!szMessage) if (tw->awi && tw->awi->message) szMessage = tw->awi->message; if ( szMessage ) awi->message = GTR_MALLOC(strlen(szMessage)+1); if (!awi->message) { GTR_FREE(awi); return; } strcpy(awi->message,szMessage); if (ewt == waitSameInteract) { if (tw->awi) ewt = tw->awi->ewt; else ewt = waitFullInteract; /* same, but no previous */ } else { if (tw->awi) { if (ewt < tw->awi->ewt) { XX_DMsg(DBG_WAIT, ("WAIT_Push: nested wait states must be more restrictive - changing to %d.", tw->awi->ewt)); ewt = tw->awi->ewt; } } } awi->ewt = ewt; awi->prev = tw->awi; tw->awi = awi; if ( !awi->prev || (awi->prev->ewt != tw->awi->ewt) ) TBar_UpdateTBItems( tw ); #if 0 if (!awi->prev) TBar_UpdateTBar(tw); #endif x_SetRange(tw,0,100,1); TW_ForceHitTest(tw); x_fixup_status(tw); return; } void WAIT_Lock( BOOL bLock ) { bWaitLock = bLock; } void WAIT_SetStatusBarIcon( struct Mwin * tw, enum StatusBarIconType StatusBarIcon ) { if ( tw && tw->awi ) { tw->awi->StatusBarIcon = StatusBarIcon; BHBar_Update(tw); } } BOOL WAIT_Pop(struct Mwin * tw) { struct AsyncWaitInfo * prev; enum WaitType old_ewt; if (!tw || !tw->awi) { XX_DMsg(DBG_WAIT, ("WAIT_Pop: no awi to pop\n")); return( FALSE ); } gPushCount--; #ifdef FEATURE_IAPI if (tw->szProgressApp[0] && (gPushCount == 0)) { DDE_Issue_EndProgress(tw->szProgressApp); tw->szProgressApp[0] = '\0'; } #endif XX_DMsg(DBG_WAIT, ("WAIT_Pop: '%s' (type %d)\n", tw->awi->message, tw->awi->ewt)); if (tw->awi->message) GTR_FREE(tw->awi->message); old_ewt = tw->awi->ewt; prev = tw->awi->prev; GTR_FREE(tw->awi); tw->awi = prev; if ( !tw->awi || (old_ewt != tw->awi->ewt) ) TBar_UpdateTBItems(tw); #if 0 if (!tw->awi) TBar_UpdateTBar(tw); #endif TW_ForceHitTest(tw); x_fixup_status(tw); return( TRUE ); } void WAIT_Update(struct Mwin * tw, enum WaitType ewt, unsigned char * message) { if (!tw || !tw->awi) return; XX_DMsg(DBG_WAIT, ("WAIT_UpdateMessage: updating to '%s' (type %d)\n", message, ewt)); if ( bWaitLock ) { XX_DMsg(DBG_WAIT, ("WAIT_UpdateMessage: Returning do to lock")); return; } if (strlen(message) > strlen(tw->awi->message)) { GTR_FREE(tw->awi->message); tw->awi->message = GTR_MALLOC(strlen(message) + 1); } strcpy(tw->awi->message, message); BHBar_Update(tw); if (ewt != waitSameInteract) { enum WaitType old_ewt = tw->awi->ewt; tw->awi->ewt = ewt; if ( old_ewt != tw->awi->ewt ) TBar_UpdateTBItems(tw); } if (tw->awi->ewt < waitNoInteract) { TW_ForceHitTest(tw); } else { /* If we've gone into a non-interaction state, the previous transient message must be invalid */ BHBar_SetStatusField(tw, ""); } return; } void WAIT_UpdateWaitStack(struct Mwin * tw, enum WaitType ewt, int nFrames) { struct AsyncWaitInfo * awi; enum WaitType old_ewt; XX_DMsg(DBG_WAIT, ("WAIT_UpdateWaitStack: updating %d frames to %d", nFrames, ewt)); if (!tw || !tw->awi) return; old_ewt = tw->awi->ewt; for (awi=tw->awi; ((awi) && (nFrames)); awi=awi->prev, nFrames--) awi->ewt = ewt; if ( old_ewt != tw->awi->ewt ) TBar_UpdateTBItems(tw); if (tw->awi->ewt < waitNoInteract) { BHBar_Update(tw); } else { /* If we've gone into a non-interaction state, the previous transient message must be invalid */ BHBar_SetStatusField(tw, ""); } TW_ForceHitTest(tw); return; } void WAIT_SetTherm(struct Mwin * tw, int nScalingNumerator) { int k1,k2; if (!tw || !tw->awi) return; if ( tw->awi->nScalingDenominator < 10000 ) return; XX_DMsg(DBG_WAIT, ("WAIT_SetTherm: updating to '%d (of %d)'\n", nScalingNumerator, tw->awi->nScalingDenominator)); /* hack -- see if display would be affected */ k1 = x_ScaleTerm(tw->awi,tw->awi->nLastScalingNumerator); k2 = x_ScaleTerm(tw->awi,nScalingNumerator); XX_DMsg(DBG_WAIT, ("WAIT_SetTherm: k1=%d k2=%d\n", k1, k2)); if (k2 > k1) { /* If progress app has been specified, use DDE */ UpdateThermometer(tw,k2); tw->awi->nLastScalingNumerator = nScalingNumerator; XX_DMsg(DBG_WAIT, ("WAIT_SetTherm: DRAW\n")); } return; } enum WaitType WAIT_GetWaitType(struct Mwin *tw) { enum WaitType wtResult; if (!tw || !tw->awi) { wtResult = waitNotWaiting; } else { wtResult = tw->awi->ewt; } XX_Assert((wtResult >= waitNotWaiting && wtResult <= waitNoInteract), ("Illegal wait type found: %d", wtResult)); return wtResult; }