/* zmwin.c - windowing functions for ZM.c * * HISTORY: * 09-Mar-87 danl Move GetAliases to KeyManager * 09-Mar-87 danl Move DoScipt to first in KeyManager * 11-Apr-1987 mz Use PASCAL/INTERNAL * 15-Apr-1987 mz Fix up insufficient arguments * 05-May-87 danl Add fCheckMail * 15-Jun-87 danl KeyManager: always call GetAliases * 19-Jun-87 danl CheckMail: output current time * 29-Jun-87 danl Display current time at left of cmd title * 01-Jul-87 danl test idoc, inote against -1 not ERROR * 03-Jul-87 danl Make local string for time display: CheckMail * 15-Jul-87 danl Use fNotifyTools flags * 20-Jul-87 danl Use ReadKey instead of _getch * 21-Aug-1987 mz Change references from MAXARG to MAXLINELEN * Speed up BlankWindow * 24-Aug-1987 mz Remove unneeded argument to DownloadMail * 02-Sep-87 danl BlankWindow: more speed up * 24-Sep-87 danl Add ySize to ClearScrn call * 19-Nov-87 sz Add code for BeepOnMail * 17-Mar-1988 mz Only do periodic mail stuff if allowed * 12-Oct-1989 leefi v1.10.73, added inclusion of * 12-Oct-1989 leefi v1.10.73, added inclusion of * 12-Oct-1989 leefi v1.10.73, added inclusion of * 12-Oct-1989 leefi v1.10.73, added inclusion of * */ #define INCL_DOSINFOSEG #include #include #include #include #include #include #include #include #include #include "wzport.h" #include #include "dh.h" #include "zm.h" extern BOOL screenWriteInProgress; /* if whole window write in progress */ extern PCHAR_INFO pLocalScreen; /* local screen buffer */ HW winList = NULL; /* head of window list, active on top */ /* SendMessage - address a message to a particular window * * hWnd window for message * command command for message */ VOID SendMessage (HW hWnd, INT command, ...) { va_list vaPtr; if ( hWnd != NULL ) { va_start (vaPtr, command); (*(hWnd->wndProc)) (hWnd, command, va_arg (vaPtr, WDATA)); va_end (vaPtr); } } /* SpacePad - pad out a line to a specific length with spaces. * * SpacePad is used to forcibly blank the remainder of a line during display. * BlankLine is not useful here as we are displaying a significant portion * of the line with other-than-white-space. * * p pointer to beginning of NUL-terminated line * n length of line to pad out to. */ VOID PASCAL INTERNAL SpacePad (PSTR p, INT n) { register INT c = strlen (p); if (c < n) memset(p + c, ' ', n - c); } /* GenClip - generalized clipping/intersection of two boxes * * bgBox background box being obscured * fgBox foreground box doing the obscuring * pVisBox pointer to a subset of bgBox that will be visible * pIntBox pointer to intersection box */ VOID PASCAL INTERNAL GenClip (BOX bgBox, BOX fgBox, PBOX pVisBox, PINT pcVis, PBOX pIntBox, PINT pcInt) { PBOX pBox = NULL; if (pcVis != NULL) *pcVis = 0; if (pcInt != NULL) *pcInt = 0; /* test for absence of clipping */ if (bgBox.bottom < fgBox.top || bgBox.top > fgBox.bottom || bgBox.right < fgBox.left || bgBox.left > fgBox.right) { if (pVisBox != NULL) { *pVisBox = bgBox; (*pcVis)++; } return; } pBox = pVisBox; /* clip the top portion of background box */ if (INRANGE (bgBox.top, fgBox.top, bgBox.bottom)) { if (bgBox.top <= fgBox.top - 1 && pBox != NULL) { *pBox = bgBox; pBox->bottom = fgBox.top - 1; pBox++; (*pcVis)++; } bgBox.top = fgBox.top; } /* clip the bottom portion of background box */ if (INRANGE (bgBox.top, fgBox.bottom, bgBox.bottom)) { if (fgBox.bottom + 1 <= bgBox.bottom && pBox != NULL) { *pBox = bgBox; pBox->top = fgBox.bottom + 1; pBox++; (*pcVis)++; } bgBox.bottom = fgBox.bottom; } /* clip the left portion of the background box */ if (INRANGE (bgBox.left, fgBox.left, bgBox.right)) { if (bgBox.left <= fgBox.left - 1 && pBox != NULL) { *pBox = bgBox; pBox->right = fgBox.left - 1; pBox++; (*pcVis)++; } bgBox.left = fgBox.left; } /* clip the right portion of the background box */ if (INRANGE (bgBox.left, fgBox.right, bgBox.right)) { if (fgBox.right + 1 <= bgBox.right && pBox != NULL) { *pBox = bgBox; pBox->left = fgBox.right + 1; (*pcVis)++; } bgBox.right = fgBox.right; } if (pIntBox != NULL) { *pIntBox = bgBox; if (pcInt != NULL) *pcInt = 1; } return; } /* ApplyVis - apply a procedure to all visible portions of a box that are * obscured by all windows starting at a particular one and ending at another. * * box box that is being clipped * hWndStart beginning window to start clipping on * hWndStop window to terminate clipping * proc procedure to call on each visible portion * arg first of arguments to be passed to procedure */ VOID PASCAL INTERNAL ApplyVis (BOX box, HW hWndStart, HW hWndStop, PVISPROC proc, INT x, LPSTR p, INT a) { INT cBox, i; BOX vis[4]; if (hWndStart == NULL || hWndStart == hWndStop) (*proc) (hWndStop, box, x, p, a); else { GenClip (box, hWndStart->win, vis, &cBox, NULL, NULL); for (i = 0; i < cBox; i++) ApplyVis (vis[i], hWndStart->pNext, hWndStop, proc, x, p, a); } } /* TextBox - display text for a window. * * TextBox is called by WzTextOut to display known, visible text from a window. * The regions displayed are enumerated by ApplyVis. * * hWnd handle of window being displayed * box box being output relative to screen * x leftmost point in original string * p pointer to original string * a attribute for screen */ VOID PASCAL INTERNAL TextBox (HW hWnd, BOX box, INT x, LPSTR p, INT a) { CHAR buf[MAXLINELEN]; INT cch = box.right - box.left + 1; int i; hWnd; /* unused parameter */ // // write to local screen buffer - will also write line if minor update // for ( i = 0; i < cch; i++ ) { pLocalScreen[xSize * box.top + box.left + i].Char.AsciiChar = *(p + box.left - x + i); pLocalScreen[xSize * box.top + box.left + i].Attributes = (WORD) a; } if ( ! screenWriteInProgress) { Move (p + box.left - x, buf, cch); LineOut (box.left, box.top, buf, cch, a); } } /* WinOut - display window text mapping entire window. * * hWnd window handle to output * x, y position relative to origin of entire window * p pointer to character string to display * c number of bytes to display * a attribute to display */ VOID PASCAL INTERNAL WinOut (HW hWnd, INT x, INT y, LPSTR p, INT c, INT a) { BOX line; INT i; /* convert text output into a box */ line.top = line.bottom = y + hWnd->win.top; line.left = x + hWnd->win.left; line.right = line.left + c - 1; /* clip text box into intersection of box with window */ GenClip (line, hWnd->win, NULL, NULL, &line, &i); if (i == 0) return; /* apply textbox to all visible windows */ ApplyVis (line, winList, hWnd, TextBox, line.left, p, a ); } /* StreamOut - stream text out at the cursor location of hWnd. move text into * content region if present. handle all CR's and LF's * * arguements: * hWnd window handle to preform output in * pStr pointer to string to output * c number of chars to output * style text style, attribute byte passed to winout * * returns: * no return values * */ VOID PASCAL INTERNAL StreamOut ( HW hWnd, PSTR pStr, INT c, INT style ) { PSTR pEnd = NULL; CHAR chEnd, chTmp; INT width = TWINWIDTH ( hWnd ); INT height = TWINHEIGHT ( hWnd ); INT i, temp; chEnd = *( pStr + c ); *( pStr + c ) = '\0'; while ( c-- != 0 ) { if ( *pStr == '\r' ) { hWnd->crsrX = 0; pStr++; } else if ( *pStr == '\n' ) { ( hWnd->crsrY )++; if ( hWnd->crsrY >= height ) { ( hWnd->crsrY )--; ScrollWindow ( hWnd, 1, FORWARD ); } pStr++; } else if ( *pStr == '\b' ) { ( hWnd->crsrX )--; if ( hWnd->crsrX < 0 ) { hWnd->crsrX = width - 1; ( hWnd->crsrY )--; if ( hWnd->crsrY < 0 ) { hWnd->crsrY = 0; ScrollWindow ( hWnd, 1, BACKWRD ); } } WzTextOut ( hWnd, hWnd->crsrX, hWnd->crsrY, strBLANK, 1, DefNorm); pStr++; } else { pEnd = strbscan ( pStr, strCRLF ); chTmp = *pEnd; *pEnd = '\0'; i = strlen ( pStr ); while ( i > 0 ) { temp = min ( width - hWnd->crsrX, i ); WzTextOut ( hWnd, hWnd->crsrX, hWnd->crsrY, pStr, temp, style ); hWnd->crsrX += temp; if ( hWnd->crsrX >= width ) { hWnd->crsrX = 0; ( hWnd->crsrY )++; if ( hWnd->crsrY >= height ) { ( hWnd->crsrY )--; ScrollWindow ( hWnd, 1, FORWARD ); } } pStr += temp; i -= temp; } *pEnd = chTmp; pStr = pEnd; } if ( winList == hWnd ) SetCursor ( hWnd, hWnd->crsrX, hWnd->crsrY ); } *pStr = chEnd; return; } /* WzTextOut - display text at a particular position in the window. Perform * all clipping necessary. Perform the text output inside the * border with specified style. * * hWnd window handle to output. * x, y position relative to origin of text window to begin display * p pointer to character string to output * c number of bytes to display * style text style, attribute byte passed to winOut */ VOID PASCAL INTERNAL WzTextOut (HW hWnd, INT x, INT y, LPSTR p, INT c, INT style ) { BOX aBox; INT w = TWINWIDTH (hWnd); INT i; if ( y >= 0 && y < TWINHEIGHT ( hWnd ) && x >= 0 && x < w ) { x += hWnd->lLeft; y += 1; /* update window content region? */ if ( hWnd->pContent != NULL ) { /* clip text to window content region, note off set from hWnd->win */ aBox.top = aBox.bottom = hWnd->win.top + y; aBox.left = hWnd->win.left + x; aBox.right = aBox.left + c; GenClip ( aBox, hWnd->win, NULL, NULL, &aBox, &i ); /* translate resultant box to window content region coordinates */ aBox.top -= ( hWnd->win.top + 1 ); aBox.left -= ( hWnd->win.left + hWnd->lLeft ); aBox.right -= ( hWnd->win.left + hWnd->lLeft ); if ( i != 0 ) Move ( ( LPSTR ) p, ( LPSTR ) hWnd->pContent + ( ( aBox.top * w ) + aBox.left ) * sizeof ( CHAR ), aBox.right - aBox.left ); } WinOut (hWnd, x, y, p, min(c, w - x + 1), style); } } /* ClearLine - draw a blank line * * hWnd handle of window to blank * i index of line to blank */ VOID PASCAL INTERNAL ClearLine (HW hWnd, INT i) { INT w = TWINWIDTH (hWnd); CHAR line[MAXLINELEN]; memset ( line, ' ', w); WzTextOut (hWnd, 0, i, line, w, DefNorm); } /* DisplayTitle - display title line of a window * * hWnd handle of window */ VOID PASCAL INTERNAL DisplayTitle (HW hWnd) { INT len; INT w = TWINWIDTH (hWnd); CHAR line[MAXLINELEN]; PSTR p = line; INT i = hWnd->lLeft + hWnd->lRight; if ( hWnd->lLeft ) *p++ = (CHAR) C_TL; memset ( p, C_H, w); p += w; if ( hWnd->lRight ) *p = (CHAR) C_TR; if (hWnd->pTitle != NULL) { len = min ( strlen (hWnd->pTitle), (size_t)w ); memmove ( & line[(w + i - len)/2], (hWnd->pTitle), len); } WinOut (hWnd, 0, 0, line, w + i, DefNorm); CheckTimeDisplay ( -1L ); } /* DisplayFooter - display footer in bottom border * * hWnd handle of window */ VOID PASCAL INTERNAL DisplayFooter (HW hWnd) { INT len; INT w = TWINWIDTH (hWnd); CHAR line[MAXLINELEN]; PSTR p = line; INT y; INT i = hWnd->lLeft + hWnd->lRight; if ( !hWnd->lBottom ) return; if ( hWnd->lLeft ) *p++ = (CHAR) C_BL; memset (p, C_H, w); p += w; if ( hWnd->lRight ) *p = (CHAR) C_BR; if (hWnd->pFooter != NULL) { len = min ( strlen (hWnd->pFooter), (size_t)w - 2 ); memmove ( & line[ 2 ], (hWnd->pFooter), len); } if ( ( hWnd->pFooter !=NULL) && !strcmpis ( hWnd->pFooter, strMORE ) ) { y = hWnd->win.bottom - hWnd->win.top; WinOut (hWnd, 0, y, line, 2, DefNorm ); WinOut (hWnd, 2, y, line + 2, len, DefBold ); WinOut (hWnd, 2 + len, y, line + 2 + len, w - len -2 + i, DefNorm ); } else WinOut (hWnd, 0, hWnd->win.bottom - hWnd->win.top, line, w + i, DefNorm); } /* BlankWindow - draw a blank window. * * hWnd handle of window to blank * fBorder TRUE => draw border, FALSE => erase border */ VOID PASCAL INTERNAL BlankWindow (HW hWnd, FLAG fBorder) { INT w = TWINWIDTH (hWnd); INT iBorder = hWnd->lLeft + hWnd->lRight; INT i; CHAR line[MAXLINELEN]; PSTR p = line; if (fBorder) { /* generate upper border */ DisplayTitle (hWnd); /* generate content line * some code removed and optimized N.B. if fBorder then we only * draw border, we do NOT blank content */ if ( iBorder ) { *p = (CHAR) C_V; for (i = 0; i < TWINHEIGHT (hWnd); i++) { WinOut (hWnd, 0, i+1, p, 1, DefNorm); WinOut (hWnd, w + iBorder - 1, i + 1, p, 1, DefNorm); } } DisplayFooter (hWnd); } else { memset (line, ' ', w + iBorder); for (i = 0; i < TWINHEIGHT (hWnd) + 2; i++) WinOut (hWnd, 0, i, line, w + iBorder, DefNorm); } } /* ScrollWindow - scrolls a window which has a content region * * arguements: * hWnd handle of window * numLines number of lines to scroll it * dir direction * any +num scrolls window down (contents go up) * any -num scrolls window up (contents go down) * returns: * no return value * */ VOID PASCAL INTERNAL ScrollWindow ( HW hWnd, INT numLines, INT direction ) { INT width = TWINWIDTH ( hWnd ); INT height = TWINHEIGHT ( hWnd ); INT cbContent; INT cbBlank; INT cbMove; if ((hWnd->pContent == NULL) || (numLines <= 0) || (direction == 0)) return; numLines = min (height, numLines); cbContent = width * height * sizeof ( CHAR ); cbBlank = width * numLines * sizeof ( CHAR ); cbMove = cbContent - cbBlank; /* cbContent number of bytes in total content region * cbBlank number of bytes of blanking * cbMove number of bytes to move */ if (direction > 0) { if (cbMove > 0) Move ((LPSTR) (hWnd->pContent + cbBlank), (LPSTR) hWnd->pContent, cbMove); Fill ((LPSTR) (hWnd->pContent + cbMove), ' ', cbBlank); } else { if (cbMove > 0) Move ((LPSTR) hWnd->pContent, (LPSTR) (hWnd->pContent + cbBlank), cbMove); Fill ((LPSTR) hWnd->pContent, ' ', cbBlank); } // // If the window is on the top, // or, if the command window is on top and this is the second window, // use video scrolling. don't use video scrolling for command window. // if ( (hWnd != hCommand) && ( (hWnd == winList) || ( (winList == hCommand) && (hWnd == winList->pNext) ) ) ) { if (direction > 0 && numLines > 0) ScrollUp (hWnd->win.left+hWnd->lLeft, hWnd->win.top+1, hWnd->win.right-hWnd->lRight, hWnd->win.bottom-hWnd->lBottom, numLines, DefNorm); else if (direction < 0 && numLines > 0) ScrollDn (hWnd->win.left+hWnd->lLeft, hWnd->win.top+1, hWnd->win.right-hWnd->lRight, hWnd->win.bottom-hWnd->lBottom, numLines, DefNorm); else DrawWindow ( hWnd, FALSE ); } else DrawWindow ( hWnd, FALSE ); return; } /* DrawWindow - displays a window and border on the the screen * * hWnd handle of window * fBorder TRUE => redraw border, FALSE => just repaint */ VOID PASCAL INTERNAL DrawWindow (HW hWnd, FLAG fBorder) { INT i; #ifdef NT SMALL_RECT screenArea; // // write whole screen as a block to the console for better performance // startScreenWrite ( ); #endif if (fBorder) BlankWindow (hWnd, TRUE); /* display all content lines */ for (i = 0; i < TWINHEIGHT (hWnd); i++) (*(hWnd->wndProc)) (hWnd, PAINT, i); #ifdef NT screenArea.Left = ( SHORT ) hWnd->win.left; screenArea.Top = ( SHORT ) hWnd->win.top; screenArea.Right = ( SHORT ) hWnd->win.right; screenArea.Bottom = (SHORT ) hWnd->win.bottom; endScreenWrite ( &screenArea ); #endif } /* FitWinToScrn - make sure a box can fit on the screen, shrink it if necessary. * * arguments: * pBox pointer to box to check * * return value: * none. box pointed to by pBox is set to fit on screen * * IMPORTANT: * FitWinToScrn ( ) assumes all box coordinates are positive. */ VOID PASCAL INTERNAL FitWinToScrn ( PBOX pBox ) { pBox->top = ( pBox->top >= ySize ) ? ySize - 1 : pBox->top; pBox->left = ( pBox->left >= xSize ) ? xSize - 1 : pBox->left; pBox->bottom = ( pBox->bottom >= ySize ) ? ySize - 1 : pBox->bottom; pBox->right = ( pBox->right >= xSize ) ? xSize - 1 : pBox->right; return; } /* CreateWindow - create a new window instance and put it on the top of the * window pile on the screen. Display the window too. * * x, y location of upper left corner of window on screen * xSize, ySize dimensions of the window * if xSize < 0 then permissible to not show left/right * border if they are at screen edge * if ySize < 0 then do not show bottom border * wndProc window procedure to call for input * keyProc procedure to call for undefined keys * data optional extra data to be passed to window procedure * * returns handle to window */ HW PASCAL INTERNAL CreateWindow (PSTR pTitle, INT x, INT y, INT width, INT height, PWNDPROC wndProc, PKEYPROC keyProc, WDATA data) { FLAG fNoVBorder = FALSE; FLAG fNoHBorder = FALSE; HW hTmp; if ((hTmp = (HW ) ZMalloc (sizeof (*hTmp))) == NULL) return NULL; hTmp->pTitle = pTitle == NULL ? pTitle : ZMMakeStr (pTitle); hTmp->pFooter = NULL; /* default pContent to NULL */ hTmp->pContent = NULL; hTmp->contSize = 0; hTmp->crsrX = 0; hTmp->crsrY = 0; if ( width < 0 ) { width = -width; fNoVBorder = !fWinBorders; } if ( height < 0 ) { height = - height; fNoHBorder = !fWinBorders; } SetRect ( &( hTmp->win ), y, x, y + height - 1, x + width - 1 ); FitWinToScrn ( &( hTmp->win ) ); hTmp->lLeft = ( fNoVBorder && hTmp->win.left == 0 ? 0 : 1 ); hTmp->lRight = ( fNoVBorder && hTmp->win.right == xSize - 1 ? 0 : 1 ); hTmp->lBottom= ( fNoHBorder ? 0 : 1 ); hTmp->fsFlag = WF_BLINK; hTmp->wndProc = wndProc; hTmp->keyProc = keyProc; hTmp->pNext = winList; winList = hTmp; (*wndProc) (hTmp, CREATE, data); DrawWindow ( hTmp, TRUE ); SetCursor ( hTmp, hTmp->crsrX, hTmp->crsrY ); return hTmp; } /* defWndProc - default window proc * * Handles most common operations */ VOID PASCAL INTERNAL defWndProc (HW hWnd, INT command, WDATA data) { INT width = TWINWIDTH (hWnd); INT height = TWINHEIGHT (hWnd); switch (command) { /* Paint a line on the screen. If there's a content area and * the line to be painted is within the screen, output it * from the content area */ case PAINT: if (hWnd->pContent != NULL) if ((INT)data < height) WzTextOut (hWnd, 0, (INT)data, hWnd->pContent + data * width, width, DefNorm); break; case CLOSE: if (hWnd->pContent) PoolFree (hWnd->pContent); break; case DISPLAY: SendMessage (hWnd, DISPLAYSTR, data); SendMessage (hWnd, DISPLAYSTR, strCRLF); break; case DISPLAYSTR: StreamOut ( hWnd, (PSTR) data, strlen ((PSTR) data), DefNorm); break; case REGENCONT: if (hWnd->pContent != NULL) Fill (hWnd->pContent, ' ', height * width); break; default: break; } } /* BringToTop - bring a background window to the top position. Draw it on * the screen if requested. Place the cursor at crsrX, crsrY * * hWnd handle of window to be made top * fDisplay TRUE => window is to be displayed */ VOID PASCAL INTERNAL BringToTop (HW hWnd, FLAG fDisplay) { HW hTmp, hPrev; hTmp = winList; hPrev = NULL; while (hTmp != NULL) if (hTmp == hWnd) break; else { hPrev = hTmp; hTmp = hTmp->pNext; } if (hPrev != NULL) { hPrev->pNext = hTmp->pNext; hTmp->pNext = winList; winList = hTmp; } if (fDisplay) DrawWindow (hWnd, TRUE); SetCursor ( hWnd, hWnd->crsrX, hWnd->crsrY ); return; } /* CloseWindow - remove a window from display. * * The only difficult part is to get each obscured window to redraw * themselves when the specified window is removed. We first blank the * window by redrawing (via WinOut) the window, determine the * intersections of all windows lower in the pile than the selected one, and * then calling their window procedures to paint the specified intersections. * * hWnd handle of window to close */ VOID PASCAL INTERNAL CloseWindow (HW hWnd) { HW hTmp; BOX box; INT i; #ifdef NT SMALL_RECT screenArea; #endif hTmp = hWnd->pNext; BringToTop (hWnd, FALSE); winList = winList->pNext; #ifdef NT // // write whole screen as a block to the console for better performance // startScreenWrite ( ); #endif BlankWindow (hWnd, FALSE); #ifdef NT screenArea.Left = ( SHORT ) hWnd->win.left; screenArea.Top = ( SHORT ) hWnd->win.top; screenArea.Right = ( SHORT ) hWnd->win.right; screenArea.Bottom = (SHORT ) hWnd->win.bottom; endScreenWrite ( &screenArea ); #endif NT (*(hWnd->wndProc)) (hWnd, CLOSE, 0); while (hTmp != NULL) { GenClip (hTmp->win, hWnd->win, NULL, NULL, &box, &i); if (i != 0) DrawWindow (hTmp, TRUE); hTmp = hTmp->pNext; } if (hWnd->pTitle != NULL) ZMfree (hWnd->pTitle); if (hWnd->pFooter != NULL) ZMfree (hWnd->pFooter); ZMfree (hWnd); if (winList != NULL) SetCursor ( winList, winList->crsrX, winList->crsrY ); return; } /* CloseAllWindows - remove everything from the display * returns with winList empty. * * arguements: * none * * return value: * none * */ VOID PASCAL INTERNAL CloseAllWindows (VOID) { HW hNextWnd = winList; HW hWnd; while ( hNextWnd != NULL ) { hWnd = hNextWnd; hNextWnd = hNextWnd->pNext; CloseWindow ( hWnd ); } return; } /* ResizeWindow - change the size of a window, update pContent. * * arguments: * hWnd handle to window to resize * pBox pointer to box to check * * return value: * returns TRUE if window needs repainting * * IMPORTANT : * ResizeWindow does not update the screen. */ FLAG PASCAL INTERNAL ResizeWindow ( HW hWnd, PBOX pBox ) { INT windSize = 0; FitWinToScrn ( pBox ); if (hWnd->win.left == pBox->left && hWnd->win.right == pBox->right && hWnd->win.top == pBox->top && hWnd->win.bottom == pBox->bottom) return FALSE; hWnd->win = *pBox; if (hWnd->pContent != NULL) { windSize = TWINWIDTH (hWnd) * TWINHEIGHT (hWnd) * sizeof(CHAR); if ( (UINT)windSize > hWnd->contSize ) { PoolFree ( hWnd->pContent ); hWnd->pContent = PoolAlloc ( windSize ); hWnd->contSize = windSize; } SendMessage ( hWnd, REGENCONT, NULL ); } return TRUE; } /* SetWindowText - change the title of a window * * hWnd window whose title is to be changed * pTitle new title to be changed */ VOID PASCAL INTERNAL SetWindowText (HW hWnd, PSTR pTitle) { if (hWnd->pTitle != NULL) ZMfree (hWnd->pTitle); if (pTitle != NULL) hWnd->pTitle = ZMMakeStr (pTitle); else hWnd->pTitle = NULL; DisplayTitle (hWnd); } /* SetWindowFooter - change the footer of a window * * hWnd window whose footer is to be changed * pFooter new footer to be changed */ VOID PASCAL INTERNAL SetWindowFooter (HW hWnd, PSTR pFooter) { if (hWnd->pFooter != NULL) ZMfree (hWnd->pFooter); if (pFooter != NULL) hWnd->pFooter = ZMMakeStr (pFooter); else hWnd->pFooter = NULL; DisplayFooter (hWnd); } /* SetRect - set up the coordinates of the given box * * arguments : * pBox pointer to box to set up. * top top coordinate of box. * left left coordinate of box. * bottom bottom coordinate of box. * right right coordinate of box. * * return value : * none. */ VOID PASCAL INTERNAL SetRect (PBOX pBox, INT top, INT left, INT bottom, INT right) { pBox->top = top; pBox->left = left; pBox->bottom = bottom; pBox->right = right; return; } /* KeyManager - intercept keystrokes and hand them to the active window * * We use the top of winList as the current input focus. All input is handed * to the window procedure EXCEPT for the tab key. The tab key is responsible * for placing the top window on the bottom of the stack to cycle through the * set of windows. * */ VOID PASCAL INTERNAL KeyManager (VOID) { LONG now; #if defined (HEAPCRAP) INT fHeapChk; #endif /* do script first in case in contains a password command */ if ( pInitScript ) DoScript ( hCommand, pInitScript, 0 ); if (fMailAllowed) { GetAliases ( fNotifyTools & F_LOADALIAS ); fNotifyTools &= ~(FLAG)F_LOADALIAS; NotifyTools ( ); } if ( fComposeOnBoot ) ( *( winList->wndProc ) ) ( winList, KEY, 0 ); SendMessage ( hCommand, DISPPROMPT, TRUE ); while ( ( winList != NULL ) && ( !fQuit ) ) { time ( &now ); CheckTimeDisplay ( now ); if ( pInitHdrCmd ) { DoHeaders ( hCommand, pInitHdrCmd, TRUE ); SendMessage ( hCommand, DISPPROMPT, 0 ); ZMfree ( pInitHdrCmd ); pInitHdrCmd = NULL; } /* if system has not received a char for 10 sec then checkmail */ if (fMailAllowed) CheckMail ( now ); /* time out password after (default) 6 hours in case user has * left WZMAIL running and gone home */ if ( now > lTmPassword + lPasswordAge ) ResetPassword ( ); if ( now > lTmConnect + cSecConnect ) ZMDisconnect ( ); /* On multitasking systems, it is rude to go into polling loops. * * For OS/2, we have a separate thread dedicated to reading from the * console. We clear a semaphore to let him read and then wait on * a response semaphore with the specified timeout. This avoids * polling. * * For real mode DOS, we presume that INT 16 (poll) will cause an * explicit yield to other runnable threads. */ if (kbwait (60 * 1000)) { fMailUnSeen = FALSE; do { (*winList->wndProc) ( winList, KEY, ReadKey() ); } while (!fQuit && kbwait (10000)); } #if defined (HEAPCRAP) if ( ( fHeapChk = heapchk ( ) ) != HEAPOK ) { fprintf ( stderr, "%s\n", ( fHeapChk == HEAPBADBEGIN ? "Can't find heap" : "Damaged heap" ) ); assert ( fHeapChk == HEAPOK ); } #endif } return; } VOID PASCAL INTERNAL CheckTimeDisplay ( LONG lNow ) { static INT minLast; struct tm *ptmLocal = NULL; PSTR p = NULL; if ( lNow == -1L ) { time ( &lNow ); minLast = -1; } ptmLocal = localtime ( &lNow ); if ( (hCommand != NULL) && (ptmLocal->tm_min != minLast) ) { minLast = ptmLocal->tm_min; p = asctime ( localtime ( &lNow ) ); WinOut ( hCommand, 2, 0, p, 16, DefNorm ); } } VOID PASCAL INTERNAL CheckMail ( LONG lNow ) { FLAG fFirstTime = lTmLastMail == 0L; INT idoc; INT cMsg; LONG lTemp; PSTR p = NULL; /* Don't do auto new mail * if current folder is not default folder * if wzmail invoked to compose a single message * if user is typing a command * if current folder is readonly */ if ( !fCurFldIsDefFld || fDirectComp || WindLevel != 0 || fReadOnlyCur ) return; /* Do automail if fCheckMail or first time or * (periodic checking and enough time has elapsed) * For perf reasons, order of test is inverted * Return if not fCheckMail if NOT first time && * (if not requested by user ( cSecNewmail == 0 => don't check ) or * if not enough time elapsed ) */ if ( !fCheckMail && !fFirstTime && ( !cSecNewmail || ( lNow < lTmLastMail + cSecNewmail ) ) ) return; fCheckMail = FALSE; #if (defined (OS2) | defined (NT)) if (ISFULLSCREEN && ISVISIBLE) #endif { SendMessage ( hCommand, DISPLAYSTR, "Checking mailbox ... " ); p = ZMMakeStr ( asctime ( localtime ( &lNow ) ) ); strcpy ( p+16, strBLANK ); SendMessage ( hCommand, DISPLAYSTR, p ); ZMfree ( p ); } /* Don't let connection made by auto newmail keep lazy connection open * DownloadMail updates lTmLastMail * BUT ... the first time, allow lazy connection to be made on startup */ idoc = ( inoteBold != -1 ? mpInoteIdoc [ inoteBold ] : -1 ); if ( !fFirstTime ) lTemp = lTmConnect; cMsg = DownloadMail (FALSE); if ( !fFirstTime ) lTmConnect = lTemp; Disconnect ( ); #if (defined (OS2) | defined (NT)) if (cMsg || (ISFULLSCREEN && ISVISIBLE)) #endif SendMessage ( hCommand, CLRCMDLN, 0 ); /* if first time, then find the first unread message * else don't change the "current" message */ if ( fFirstTime ) { if ( ( idoc = NextUnread ( -1 ) ) != -1 ) SendMessage ( hHeaders, GOTOIDOCALL, idoc ); } else { if ( idoc != -1 ) SendMessage ( hHeaders, GOTOIDOCALL, idoc ); } } /* Bell - make some noise */ VOID PASCAL INTERNAL Bell (VOID) { write (1, "\x07", 1); } /* SetCursor - place the visible cursor in some window * * hWnd window for cursor * x, y location of cursor in window */ VOID PASCAL INTERNAL SetCursor (HW hWnd, INT x, INT y) { if (!TESTFLAG (hWnd->fsFlag, WF_BLINK)) /* move cursor off screen */ #ifdef NT cursorInvisible (); #else cursor ( xSize + 1, ySize + 1 ); #endif else if (INRANGE (0, x, TWINWIDTH (hWnd)) && INRANGE (0, y, TWINHEIGHT (hWnd))) { cursorVisible (); cursor (x + hWnd->lLeft + hWnd->win.left, y + 1 + hWnd->win.top); } } /* ShowCursor - place the visible cursor in some window * * hWnd window for cursor * fBlink TRUE -> blinking cursor, FALSE no cursor */ VOID PASCAL INTERNAL ShowCursor (HW hWnd, FLAG fBlink ) { RSETFLAG (hWnd->fsFlag, WF_BLINK); if (fBlink) SETFLAG (hWnd->fsFlag, WF_BLINK); if ( winList == hWnd ) { SetCursor ( hWnd, hWnd->crsrX, hWnd->crsrY ); #ifdef NT if (fBlink) { cursorVisible (); } #endif } } /* RedrawScreen - blank the screen and redraw all windows in the pile. */ VOID PASCAL INTERNAL RedrawScreen (VOID) { HW hWnd = winList; // ClearScrn ( DefNorm, ySize ); do { DrawWindow ( hWnd, TRUE ); hWnd = hWnd->pNext; } while ( hWnd != NULL ); SetCursor ( winList, winList->crsrX, winList->crsrY ); return; } VOID PASCAL INTERNAL FreeContents (VOID) { HW hWnd; for (hWnd = winList; hWnd != NULL; hWnd = hWnd->pNext) if (!TESTFLAG (hWnd->fsFlag, WF_NODISCARD) && hWnd->pContent != NULL) { PoolFree(hWnd->pContent); hWnd->pContent = NULL; } } VOID PASCAL INTERNAL RestoreContents (VOID) { HW hWnd; for (hWnd = winList; hWnd != NULL; hWnd = hWnd->pNext) if ((hWnd->pContent == NULL) && (hWnd->contSize > 0)) if (hWnd->pContent = PoolAlloc(hWnd->contSize)) SendMessage ( hWnd, REGENCONT, NULL ); else { ZMDisconnect(); ZMexit(-1, "Out of memory for window buffers\n"); } }