diff options
Diffstat (limited to 'private/oleutest/server2/wterm.c')
-rw-r--r-- | private/oleutest/server2/wterm.c | 1029 |
1 files changed, 1029 insertions, 0 deletions
diff --git a/private/oleutest/server2/wterm.c b/private/oleutest/server2/wterm.c new file mode 100644 index 000000000..a8ef70b01 --- /dev/null +++ b/private/oleutest/server2/wterm.c @@ -0,0 +1,1029 @@ +/**************************************************************************** + + PROGRAM: wterm.c + + PURPOSE: Implementation of TermWClass Windows + + FUNCTIONS: + + + COMMENTS: + + +****************************************************************************/ + +#include "windows.h" +#include "stdlib.h" +#include "memory.h" +#include "wterm.h" + +#define MAX_ROWS 24 +#define MAX_COLS 80 + +typedef struct WData +{ + // Function to execute for processing a menu + MFUNCP pMenuProc; + + // Function to execute for processing a single character + CFUNCP pCharProc; + + // Function to execute when window is closed (terminated) + TFUNCP pCloseProc; + + // Pass on callback + void *pvCallBackData; + + BOOL fGotFocus; + + BOOL fCaretHidden; + + // Rows on the screen + int cRows; + + // Columns on the screen + int cCols; + + // Row at top of screen + int iTopRow; + + // Row at bottom of the screen + int iBottomRow; + + // First Column on screen + int iFirstCol; + + // Column at bottom of the screen + int iBottomCol; + + // Row for next character + int iNextRow; + + // Row for next column + int iNextCol; + + // Width of character + int cxChar; + + // Height of character + int cyChar; + + // Memory image of screen this is treated as a circular buffer + TCHAR aImage[MAX_ROWS] [MAX_COLS]; + + // First row in circular screen buffer + int iBufferTop; +} WData; + +static HANDLE hInst = 0; +TCHAR BlankLine[80]; + +static int +row_diff( + int row1, + int row2) +{ + return (row2 > row1) + ? MAX_ROWS - (row2 - row1) + : row1 - row2; +} + +static void +set_vscroll_pos( + HWND hwnd, + WData *pwdata) +{ + if (pwdata->cRows != 0) + { + // Save a few indirections by caching cRows + register int cRows = pwdata->cRows; + + // calculate distance bottom of screen from top of data buffer + register int top_from_row = row_diff(pwdata->iBottomRow, + pwdata->iBufferTop); + + // Output position of scroll bar + int new_pos = 0; + + if (top_from_row >= cRows) + { + // Calculate number of screens to display entire buffer + int screens_for_data = MAX_ROWS / cRows + + ((MAX_ROWS % cRows != 0) ? 1 : 0); + + // Figure out which screen the row falls in + int screen_loc = top_from_row / cRows + + ((top_from_row % cRows != 0) ? 1 : 0); + + // If the screen is in the last one set box to max + new_pos = (screen_loc == screens_for_data) + ? MAX_ROWS : screen_loc * cRows; + } + + SetScrollPos(hwnd, SB_VERT, new_pos, TRUE); + } +} + +static int +calc_row( + register int row, + WData *pwdata) +{ + register int top = pwdata->iTopRow; + static int boopa = 0; + + if (top > row) + boopa++; + + return (row >= top) ? row - top : (MAX_ROWS - (top - row)); +} + +static void +display_text( + HWND hwnd, + int row, + int col, + LPTSTR text, + int text_len, + WData *pWData) +{ + // Get the DC to display the text + HDC hdc = GetDC(hwnd); + + // Select Font + SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); + + // Hide caret while we are printing + HideCaret(hwnd); + + // Update the screen + TextOut(hdc, (col - pWData->iFirstCol) * pWData->cxChar, + calc_row(row, pWData) * pWData->cyChar, text, text_len); + + // Done with DC + ReleaseDC(hwnd, hdc); + + // Put the caret back now that we are done + ShowCaret(hwnd); +} + +static void +display_char( + HWND hwnd, + TCHAR char_to_display, + WData *pWData) +{ + // Update image buffer + pWData->aImage[pWData->iNextRow][pWData->iNextCol] = char_to_display; + + display_text(hwnd, pWData->iNextRow, pWData->iNextCol, + &char_to_display, 1, pWData); +} + +static void +do_backspace( + HWND hwnd, + WData *pWData) +{ + // Point to the previous character in the line + if (--pWData->iNextCol < 0) + { + // Can't backspace beyond the current line + pWData->iNextCol = 0; + return; + } + + display_char(hwnd, ' ', pWData); + + // Null character for repaint + pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0'; +} + +static int +inc_row( + int row, + int increment) +{ + row += increment; + + if (row >= MAX_ROWS) + { + row -= MAX_ROWS; + } + else if (row < 0) + { + row += MAX_ROWS; + } + + return row; +} + +void +inc_next_row( + HWND hwnd, + WData *pWData) +{ + if (pWData->iNextRow == pWData->iBottomRow) + { + // Line is at bottom -- scroll the client area one row + ScrollWindow(hwnd, 0, -pWData->cyChar, NULL, NULL); + + // Increment the top & bottom of the screen + pWData->iTopRow = inc_row(pWData->iTopRow, 1); + pWData->iBottomRow = inc_row(pWData->iBottomRow, 1); + } + + // Increment the row + pWData->iNextRow = inc_row(pWData->iNextRow, 1); + + if (pWData->iNextRow == pWData->iBufferTop) + { + // Have to reset circular buffer to next + pWData->iBufferTop = inc_row(pWData->iBufferTop, 1); + + // Reset line to nulls for repaint + memset(&pWData->aImage[pWData->iNextRow][0], '\0', MAX_COLS); + } + + pWData->iNextCol = 0; +} + +static void +do_cr( + HWND hwnd, + WData *pWData) +{ + // Set position to next row + inc_next_row(hwnd, pWData); + pWData->iNextCol = 0; + + // Make sure next character is null for repaint of line + pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0'; + + // Update the vertical scroll bar's position + set_vscroll_pos(hwnd, pWData); +} + +static void +do_char( + HWND hwnd, + WPARAM wParam, + WData *pWData) +{ + display_char(hwnd, (TCHAR) wParam, pWData); + + // Point to the next character in the line + if (++pWData->iNextCol > MAX_COLS) + { + // Handle switch to next line + inc_next_row(hwnd, pWData); + } +} + +static void +do_tab( + HWND hwnd, + WData *pWData) +{ + int c = pWData->iNextCol % 8; + + if ((pWData->iNextCol + c) <= MAX_COLS) + { + for ( ; c; c--) + { + do_char(hwnd, ' ', pWData); + } + } + else + { + do_cr(hwnd, pWData); + } +} + +static void +EchoChar( + HWND hwnd, + WORD cRepeats, + WPARAM wParam, + WData *pWData) +{ + for ( ; cRepeats; cRepeats--) + { + switch (wParam) + { + // Backspace + case '\b': + do_backspace(hwnd, pWData); + break; + + // Carriage return + case '\n': + case '\r': + do_cr(hwnd, pWData); + break; + + // Tab + case '\t': + do_tab(hwnd, pWData); + break; + + // Regular characters + default: + do_char(hwnd, wParam, pWData); + } + } + + // The row is guaranteed to be on the screen because we will + // scroll on a CR. However, the next column for input may be + // beyond the window we are working in. + if (pWData->iNextCol > pWData->iBottomCol) + { + // We are out of the window so scroll the window one + // column to the right. + SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, 0L); + } + else if (pWData->iNextCol < pWData->iFirstCol) + { + // We are out of the window so repaint the window using + // iNextCol as the first column for the screen. + pWData->iFirstCol = pWData->iNextCol; + pWData->iBottomCol = pWData->iFirstCol + pWData->cCols - 1; + + // Reset scroll bar + SetScrollPos(hwnd, SB_HORZ, pWData->iFirstCol, TRUE); + + // Tell window to update itself. + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + } + else + { + // Reset Caret's position + SetCaretPos((pWData->iNextCol - pWData->iFirstCol) * pWData->cxChar, + calc_row(pWData->iNextRow, pWData) * pWData->cyChar); + } +} + +/**************************************************************************** + + FUNCTION: WmCreate(HWND) + + PURPOSE: Initializes control structures for a TermWClass Window + + MESSAGES: + WM_CREATE + + COMMENTS: + + This prepares a window for processing character based + I/O. In particular it does stuff like calculate the + size of the window needed. + +****************************************************************************/ +static void +WmCreate( + HWND hwnd, + CREATESTRUCT *pInit) +{ + WData *pData = (WData *) (pInit->lpCreateParams); + HDC hdc = GetDC(hwnd); + TEXTMETRIC tm; + + // Store pointer to window data + SetWindowLong(hwnd, 0, (LONG) pData); + + // Set font to system fixed font + SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); + + // Calculate size of a character + GetTextMetrics(hdc, &tm); + pData->cxChar = tm.tmAveCharWidth; + pData->cyChar = tm.tmHeight; + ReleaseDC(hwnd, hdc); + + // Set up vertical scroll bars + SetScrollRange(hwnd, SB_VERT, 0, MAX_ROWS, TRUE); + SetScrollPos(hwnd, SB_VERT, 0, TRUE); + + // Set up horizontal scroll bars + SetScrollRange(hwnd, SB_HORZ, 0, MAX_COLS, TRUE); + SetScrollPos(hwnd, SB_HORZ, 0, TRUE); +} + +/**************************************************************************** + + FUNCTION: WmSize(HWND, WORD, LONG) + + PURPOSE: Processes a size message + + MESSAGES: + + COMMENTS: + +****************************************************************************/ +static void +WmSize( + HWND hwnd, + WPARAM wParam, + LONG lParam, + WData *pwdata) +{ + // Get the new size of the window + int cxClient; + int cyClient; + int cRowChange = pwdata->cRows; + RECT rect; + + // Get size of client area + GetClientRect(hwnd, &rect); + + // Calculate size of client area + cxClient = rect.right - rect.left; + cyClient = rect.bottom - rect.top; + + // Calculate size of area in rows + pwdata->cCols = cxClient / pwdata->cxChar; + pwdata->cRows = min(MAX_ROWS, cyClient / pwdata->cyChar); + pwdata->iBottomCol = min(pwdata->iFirstCol + pwdata->cCols, MAX_COLS); + cRowChange = pwdata->cRows - cRowChange; + + // Keep input line toward bottom of screen + if (cRowChange < 0) + { + // Screen has shrunk in size. + if (pwdata->iNextRow != pwdata->iTopRow) + { + // Has input row moved out of screen? + if (row_diff(pwdata->iNextRow, pwdata->iTopRow) >= pwdata->cRows) + { + // Yes -- Calculate top new top that puts input line on + // the bottom. + pwdata->iTopRow = + inc_row(pwdata->iNextRow, 1 - pwdata->cRows); + } + } + } + else + { + // Screen has gotten bigger -- Display more text if possible + if (pwdata->iTopRow != pwdata->iBufferTop) + { + pwdata->iTopRow = inc_row(pwdata->iTopRow, + -(min(row_diff(pwdata->iTopRow, pwdata->iBufferTop), + cRowChange))); + } + } + + // Calculate new bottom + pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows - 1); + + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); +} + +static void +WmSetFocus( + HWND hwnd, + WData *pwdata) +{ + // save indirections + register int cxchar = pwdata->cxChar; + register int cychar = pwdata->cyChar; + pwdata->fGotFocus = TRUE; + CreateCaret(hwnd, NULL, cxchar, cychar); + + if (!pwdata->fCaretHidden) + { + SetCaretPos(pwdata->iNextCol * cxchar, + calc_row(pwdata->iNextRow, pwdata) * cychar); + } + + ShowCaret(hwnd); +} + +static void +WmKillFocus( + HWND hwnd, + WData *pwdata) +{ + pwdata->fGotFocus = FALSE; + + if (!pwdata->fCaretHidden) + { + HideCaret(hwnd); + } + + DestroyCaret(); +} + +static void +WmVscroll( + HWND hwnd, + WPARAM wParam, + LONG lParam, + WData *pwdata) +{ + int cVscrollInc = 0; + register int top_diff = row_diff(pwdata->iTopRow, pwdata->iBufferTop); + register int bottom_diff = MAX_ROWS - (top_diff + pwdata->cRows); + + switch(wParam) + { + case SB_TOP: + + if (top_diff != 0) + { + cVscrollInc = -top_diff; + } + + break; + + case SB_BOTTOM: + + if (bottom_diff != 0) + { + cVscrollInc = bottom_diff; + } + + break; + + case SB_LINEUP: + + if (top_diff != 0) + { + cVscrollInc = -1; + } + + break; + + case SB_LINEDOWN: + + if (bottom_diff != 0) + { + cVscrollInc = 1; + } + + break; + + case SB_PAGEUP: + + if (top_diff != 0) + { + cVscrollInc = - ((top_diff > pwdata->cRows) + ? pwdata->cRows : top_diff); + } + + break; + + case SB_PAGEDOWN: + + if (bottom_diff != 0) + { + cVscrollInc = (bottom_diff > pwdata->cRows) + ? pwdata->cRows : bottom_diff; + } + + break; + + case SB_THUMBTRACK: + + if (LOWORD(lParam) != 0) + { + cVscrollInc = LOWORD(lParam) + - row_diff(pwdata->iTopRow, pwdata->iBufferTop); + } + } + + // Cacluate new top row + if (cVscrollInc != 0) + { + // Calculate new top and bottom + pwdata->iTopRow = inc_row(pwdata->iTopRow, cVscrollInc); + pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows); + + // Scroll window + ScrollWindow(hwnd, 0, pwdata->cyChar * cVscrollInc, NULL, NULL); + + // Reset scroll bar + set_vscroll_pos(hwnd, pwdata); + + // Tell window to update itself. + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + } +} + +static void +WmHscroll( + HWND hwnd, + WPARAM wParam, + LONG lParam, + WData *pwdata) +{ + register int cHscrollInc = 0; + + switch(wParam) + { + case SB_LINEUP: + + cHscrollInc = -1; + break; + + case SB_LINEDOWN: + + cHscrollInc = 1; + break; + + case SB_PAGEUP: + + cHscrollInc = -8; + break; + + case SB_PAGEDOWN: + + cHscrollInc = 8; + break; + + case SB_THUMBTRACK: + + if (LOWORD(lParam) != 0) + { + cHscrollInc = LOWORD(lParam) - pwdata->iFirstCol; + } + } + + if (cHscrollInc != 0) + { + // Cacluate new first column + register int NormalizedScrollInc = cHscrollInc + pwdata->iFirstCol; + + if (NormalizedScrollInc < 0) + { + cHscrollInc = -pwdata->iFirstCol; + } + else if (NormalizedScrollInc > MAX_COLS - pwdata->cCols) + { + cHscrollInc = (MAX_COLS - pwdata->cCols) - pwdata->iFirstCol; + } + + pwdata->iFirstCol += cHscrollInc; + pwdata->iBottomCol = pwdata->iFirstCol + pwdata->cCols - 1; + + // Scroll window + ScrollWindow(hwnd, -(pwdata->cxChar * cHscrollInc), 0, NULL, NULL); + + // Reset scroll bar + SetScrollPos(hwnd, SB_HORZ, pwdata->iFirstCol, TRUE); + + // Tell window to update itself. + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + } +} + +static void +WmPaint( + HWND hwnd, + WData *pwdata) +{ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + register int row = pwdata->iTopRow; + register int col = pwdata->iFirstCol; + int bottom_row = pwdata->iBottomRow; + int cxChar = pwdata->cxChar; + int cyChar = pwdata->cyChar; + int y; + + // Select System Font + SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); + + while (TRUE) + { + int len = lstrlen(&pwdata->aImage[row][col]); + + if (len != 0) + { + y = calc_row(row, pwdata) * cyChar; + TextOut(hdc, 0, y, &pwdata->aImage[row][col], len); + } + + if (row == bottom_row) + { + break; + } + + row = inc_row(row, 1); + } + + if (pwdata->fGotFocus) + { + if ((pwdata->iNextCol >= pwdata->iFirstCol) + && (row_diff(pwdata->iNextRow, pwdata->iTopRow) < pwdata->cRows)) + { + if (pwdata->fCaretHidden) + { + pwdata->fCaretHidden = FALSE; + ShowCaret(hwnd); + } + + SetCaretPos( + (pwdata->iNextCol - pwdata->iFirstCol) * pwdata->cxChar, + calc_row(pwdata->iNextRow, pwdata) * pwdata->cyChar); + } + else + { + if (!pwdata->fCaretHidden) + { + pwdata->fCaretHidden = TRUE; + HideCaret(hwnd); + } + } + } + + EndPaint(hwnd, &ps); +} + + + + + +// +// FUNCTION: WmPrintLine +// +// PURPOSE: Print a line on the screen. +// +// Note: this is a user message not an intrinsic Window's message. +// +void +WmPrintLine( + HWND hwnd, + WPARAM wParam, + LONG lParam, + WData *pTermData) +{ + TCHAR *pBuf = (TCHAR *) lParam; + + // MessageBox(hwnd, L"WmPrintLine", L"Debug", MB_OK); + + // DebugBreak(); + + while (wParam--) + { + // Is character a lf? + if (*pBuf == '\n') + { + // Convert to cr since that is what this window uses + *pBuf = '\r'; + } + + // Write the character to the window + EchoChar(hwnd, 1, *pBuf++, pTermData); + } + +} + +// +// FUNCTION: WmPutc +// +// PURPOSE: Print a single character on the screen +// +// Note: this is a user message not an intrinsic Window's message. +// +void +WmPutc( + HWND hwnd, + WPARAM wParam, + WData *pTermData) +{ + // Is character a lf? + if (wParam == '\n') + { + // Convert to cr since that is what this window uses + wParam = '\r'; + } + + // Write the character to the window + EchoChar(hwnd, 1, wParam, pTermData); +} + + +/**************************************************************************** + + FUNCTION: TermWndProc(HWND, unsigned, WORD, LONG) + + PURPOSE: Processes messages + + MESSAGES: + + COMMENTS: + +****************************************************************************/ + +long TermWndProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + WData *pTerm = (WData *) GetWindowLong(hWnd, 0); + + switch (message) + { + case WM_CREATE: + WmCreate(hWnd, (CREATESTRUCT *) lParam); + break; + + case WM_COMMAND: + case WM_SYSCOMMAND: + // Call procedure that processes the menus + return (*(pTerm->pMenuProc))(hWnd, message, wParam, lParam, + pTerm->pvCallBackData); + + case WM_SIZE: + WmSize(hWnd, wParam, lParam, pTerm); + break; + + case WM_SETFOCUS: + WmSetFocus(hWnd, pTerm); + break; + + case WM_KILLFOCUS: + WmKillFocus(hWnd, pTerm); + break; + + case WM_VSCROLL: + WmVscroll(hWnd, wParam, lParam, pTerm); + break; + + case WM_HSCROLL: + WmHscroll(hWnd, wParam, lParam, pTerm); + break; + + case WM_CHAR: + // Character message echo and put in buffer + return (*(pTerm->pCharProc))(hWnd, message, wParam, lParam, + pTerm->pvCallBackData); + + case WM_PAINT: + WmPaint(hWnd, pTerm); + break; + + case WM_USER: + case WM_CLOSE: + DestroyWindow(hWnd); + break; + + case WM_NCDESTROY: + // Call close notification procedure + return (*(pTerm->pCloseProc))(hWnd, message, wParam, lParam, + pTerm->pvCallBackData); + + case WM_PRINT_LINE: + WmPrintLine(hWnd, wParam, lParam, pTerm); + break; + + case WM_PUTC: + WmPutc(hWnd, wParam, pTerm); + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_TERM_WND: + DestroyWindow(hWnd); + break; + + default: /* Passes it on if unproccessed */ + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + + return 0; +} + + +/**************************************************************************** + + FUNCTION: TermRegisterClass(HANDLE) + + PURPOSE: Register a class for a terminal window + + COMMENTS: + + +****************************************************************************/ + +BOOL TermRegisterClass( + HANDLE hInstance, + LPTSTR MenuName, + LPTSTR ClassName, + LPTSTR Icon) +{ + WNDCLASS wc; + BOOL retVal; + + // Make sure blank line is blank + memset(BlankLine, ' ', 80); + + /* Fill in window class structure with parameters that describe the */ + /* main window. */ + + wc.style = 0; + wc.lpfnWndProc = TermWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(WData *); + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, Icon); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = MenuName; + wc.lpszClassName = ClassName; + + /* Register the window class and return success/failure code. */ + if (retVal = RegisterClass(&wc)) + { + // Class got registered -- so finish set up + hInst = hInstance; + } + + return retVal; +} + + +/**************************************************************************** + + FUNCTION: TermCreateWindow(LPWSTR, LPWSTR, HMENU, void *, void *, int) + + PURPOSE: Create a window of a previously registered window class + + COMMENTS: + + +****************************************************************************/ + +BOOL +TermCreateWindow( + LPTSTR lpClassName, + LPTSTR lpWindowName, + HMENU hMenu, + MFUNCP MenuProc, + CFUNCP CharProc, + TFUNCP CloseProc, + int nCmdShow, + HWND *phNewWindow, + void *pvCallBackData) +{ + HWND hWnd; // Main window handle. + WData *pTermData; + + // Allocate control structure for the window + if ((pTermData = malloc(sizeof(WData))) == NULL) + { + return FALSE; + } + + // Set entire structure to nulls + memset((TCHAR *) pTermData, '\0', sizeof(WData)); + + // Initialize function pointers + pTermData->pMenuProc = MenuProc; + pTermData->pCharProc = CharProc; + pTermData->pCloseProc = CloseProc; + + // Initialize callback data + pTermData->pvCallBackData = pvCallBackData; + + // Create a main window for this application instance. + hWnd = CreateWindow( + lpClassName, + lpWindowName, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + hMenu, + hInst, + (LPTSTR) pTermData + ); + + // If window could not be created, return "failure" + + if (!hWnd) + { + free(pTermData); + return FALSE; + } + + // BUGBUG - Why would we want to set focus? + // SetFocus(hWnd); + + // Make the window visible; update its client area; and return "success" + + // ShowWindow(hWnd, nCmdShow); + // UpdateWindow(hWnd); + *phNewWindow = hWnd; + return (TRUE); +} |