/* * Pundit.c * Source for Pundit * * Author: Jeff Bienstadt * * Environment: * * Run-Time: Microsoft Windows 3.0 * * Compilers/Tools: * Microsoft C 6.0 * Microsoft Windows SDK 3.0 * */ #include // All the Windows goodies #include // for rand() and srand() #include // for sprintf() #include // for time() #include "pundit.h" // constants for Pundit // The structure for all the settings typedef struct _settings { int insecs, // time window is shown (in seconds) outsecs, // time window is gone (in seconds) x, // X position of window (in device units) y, // Y position of window (in device units) width, // width of window (in device units) height; // height of window (in device units) } SETTINGS; // Function Prototypes long FAR PASCAL WndProc(HWND, WORD, WORD, LONG); BOOL FAR PASCAL Settings(HWND, unsigned, WORD, LONG); BOOL FAR PASCAL About(HWND, unsigned, WORD, LONG); void FetchSettings(void); void SaveSettings(HWND); void InitSettings(HWND); void InitGlobals(HANDLE); // Global variables int count; // counts seconds window is hidden/visible WORD string_number; // store ID from string table here BOOL inout_state, // are we shown or hidden? paused; // ...... paused or couning? HANDLE hinst; // a global Instance Handle HWND jkbPundit; // a global Window Handle (for main window) SETTINGS settings; // the settings structure char szAppName[] = "jkbPundit"; // The (internal) Application Name // The main Window Procedure int PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow) HANDLE hInstance, // Instance Handle hPrevInstance; // Previous Instance Handle LPSTR lpszCmdLine; // The Command Line (we don't use it here) int nCmdShow; // The SHOW Method (we don't use this, either) { MSG msg; // a place to store Windows' Messages WNDCLASS wndclass; // a Window Class structure // If we have NOT already defined our Window Class, do so now... // (see the SDK documentation for how this works) if (!hPrevInstance) { wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; // wndclass.cbWndExtra = DLGWINDOWEXTRA; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = COLOR_WINDOW+1; wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; RegisterClass(&wndclass); // Register the Window Class } InitGlobals(hInstance); // Initialize Global Varaibles; // Create the Window, and put it's handle into our global Window Handle jkbPundit = CreateWindow(szAppName, // Window Name "Pundit: " "Quote of the Moment", // Window Caption WS_OVERLAPPED | // an Overlapped Window... WS_CAPTION | // with a Caption, WS_THICKFRAME | // a Sizeable Frame, WS_SYSMENU, // and a System Menu settings.x, // X position of Window settings.y, // Y position of Window settings.width, // Width of Window settings.height, // Height of Window NULL, // No Parent NULL, // Use the Class menu hInstance, // Instance for Window NULL); // No additional params // Try to get a timer... keep trying until we get one or the user gives up while (!SetTimer(jkbPundit, ID_TIMER, 1000, NULL)) { if (IDCANCEL == MessageBox(jkbPundit, "I need a Timer, but Windows won't lemme" "have one\012" "(maybe you could close a clock" "or something...)", szAppName, MB_ICONEXCLAMATION | MB_RETRYCANCEL)) return FALSE; // User gave up, bail out } ShowWindow(jkbPundit, SW_SHOWNORMAL); // Display our Window UpdateWindow(jkbPundit); // Update our Window while (GetMessage(&msg, NULL, 0, 0)) { // Fetch a Message from Windows TranslateMessage(&msg); // Translate Keyboard Messages DispatchMessage(&msg); // Pass Message on to our callback function } // until we get a QUIT Message return msg.wParam; // return to Windows } // end of WinMain // Initialize Global Variables void InitGlobals(hInstance) HANDLE hInstance; // our Instance Handle { time_t ltime; // here we store the system time settings.insecs = 5; // "Default" IN seconds settings.outsecs = 20; // "Default" OUT seconds settings.x = 1; // "Default" X position settings.y = 1; // "Default" Y position settings.width = 250; // "Default" Width settings.height = 150; // "Default" Height FetchSettings(); // Now read settings from WIN.INI count = 0; // Zero out the counter paused = FALSE; // We're not paused yet inout_state = TRUE; // We're in the "show" state hinst = hInstance; // Save our current Instance time(<ime); // Get the current time srand((unsigned)ltime); // Use it to set the random number "seed" // Create the first string table ID string_number = (rand() % MAX_STRING) + 1; } // Our main Window ``callback'' function long FAR PASCAL WndProc(hwnd, message, wParam, lParam) HWND hwnd; // Window Handle for our Window WORD message, // The Window's Message wParam; // The WORD parameter value LONG lParam; // The LONG parameter value { PAINTSTRUCT ps; // a Paint structure (for painting the Window) HDC hdc; // a Display Context Handle (for writing text) RECT rect; // a Rectangle structure (for writing text) FARPROC lpProcAbout, // Pointer to function for "About" dialog lpSettingsDialog; //.................."Settings" dialog char str_buffer[256]; // buffer for string from string table switch (message) { // check for messages... case WM_INITMENU: // if a Menu is displayed... SendMessage(hwnd, WM_jkb_PAUSE, 0, 0L); // ...stop the timer break; case WM_MENUSELECT: // if a Menu has been canceled... if ((LOWORD(lParam) == 0xFFFF) && (HIWORD(lParam) == 0)) SendMessage(hwnd, WM_jkb_START, 0, 0L); // ...restart the timer break; case WM_COMMAND: // we got a Menu choice... switch (wParam) { // ... which one? case IDM_ABOUT: // About Pundit... // Make a function Instance lpProcAbout = MakeProcInstance(About, hinst); // Process the "About" dialog box DialogBox(hinst, "ABOUTBOX", hwnd, lpProcAbout); // Give back the function Instance FreeProcInstance(lpProcAbout); // Restart the timer SendMessage(hwnd, WM_jkb_START, 0, 0L); break; case IDM_SETTINGS: // Settings... // Make a function Instance lpSettingsDialog = MakeProcInstance(Settings, hinst); // Process the "About" dialog box DialogBox(hinst, "SETTINGS", hwnd, lpSettingsDialog); // Give back the function Instance FreeProcInstance(lpSettingsDialog); // Restart the timer SendMessage(hwnd, WM_jkb_START, 0, 0L); break; case IDM_EXIT: // Exit // Tell Windows to shut down this Application PostMessage(hwnd, WM_CLOSE, 0, 0L); break; } return 0L; // return 0 exit code case WM_TIMER: // We got a TIMER Message switch (inout_state) { // are we visible or hidden? case FALSE: // hidden... if (count >= settings.outsecs) { // if it's time to show up // create a new string table ID string_number = (rand() % MAX_STRING) + 1; ShowWindow(hwnd, SW_SHOW); // Show ourselves // Tell Windows that we want to paint the entire client area InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); // Update the window inout_state = TRUE; // switch the state count = 0; // reset the counter } else // still waiting to show up ++count; // bump the counter break; case TRUE: // shown... if (count >= settings.insecs) { // if it's time to sleep ShowWindow(hwnd, SW_HIDE); // hide inout_state = FALSE; // switch the state count = 0; // reset the counter } else // still waiting to sleep ++count; // bump the counter break; } return 0L; case WM_PAINT: // We got a PAINT Message GetClientRect(hwnd, &rect); // Get the dimensions of the client area // Fetch a new string from the string table LoadString(hinst, string_number, str_buffer, 256); // Tell Windows we are ready to paint // and get a Display Context Handle hdc = BeginPaint(hwnd, &ps); // Set Background Color to Windows' Background Color SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); // Set Text Color to Windows' Text Color SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); // Write the new quote DrawText(hdc, // our Display Context Handle (LPSTR)str_buffer, // our new Quote String -1, // let Windows figure the length &rect, // write into entire client area rectangle DT_LEFT | // left-justified, DT_NOPREFIX | // `&' character are not special DT_WORDBREAK); // let Windows handle word-wrap EndPaint(hwnd, &ps); // Tell Windows that we're done painting return 0L; // These next two Messages are our own messages, NOT Windows' case WM_jkb_PAUSE: // We need to shut down the timer if (paused == FALSE) // are we already shut down? KillTimer(hwnd, ID_TIMER); // no, shut it down paused = TRUE; // and keep track of that fact return 0L; case WM_jkb_START: // We need to restart the timer if (paused == TRUE) // are we shut down now? SetTimer(hwnd, ID_TIMER, 1000, NULL); // yes, set timer for 1 sec. paused = FALSE; // and keep track of that fact return 0L; case WM_DESTROY: // We got a DESTROY Message KillTimer(hwnd, ID_TIMER); // Shut down the timer PostQuitMessage(0); // Post a QUIT Message return 0L; } // We don't need to handle any other messages, but // Windows might, so let it see them return DefWindowProc(hwnd, message, wParam, lParam); } // end of WndProc // About Box manager function BOOL FAR PASCAL About(hDlg, message, wParam, lParam) HWND hDlg; // Window Handle for our Dialog Box unsigned message; // The Window's Message WORD wParam; // The WORD parameter value LONG lParam; // The LONG parameter value { switch (message) { // check for messages... case WM_INITDIALOG: // If the Dialog is just starting... PostMessage(jkbPundit, WM_jkb_PAUSE, 0, 0L); // shut down the timer return TRUE; case WM_COMMAND: // We got a COMMAND // if the Dialog's button was pressed if (wParam == IDOK || wParam == IDCANCEL) { EndDialog(hDlg, TRUE); // That's the end of the Dialog return TRUE; // Say that we processed this message } break; } return FALSE; // Say that we did NOT process the message } HWND hInScroll, // Handle for IN scrollbar hOutScroll; // Handle for OUT scrollbar SETTINGS s; // a temporary values for settings BOOL FAR PASCAL Settings(hDlg, message, wParam, lParam) HWND hDlg; // Window Handle for our Dialog Box unsigned message; // The Window's Message WORD wParam; // The WORD parameter value LONG lParam; // The LONG parameter value { HWND hsb; // Handle for a Horizontal Scroll Bar char temp[10]; // string to write "numbers" into switch (message) { // check for messages... case WM_INITDIALOG: // If the Dialog is just starting... PostMessage(jkbPundit, WM_jkb_PAUSE, 0, 0L); // shut down the timer InitSettings(hDlg); // Initialize the Settings Dialog return TRUE; case WM_HSCROLL: // We got a Horizontal Scroll Bar Message... if (hsb = HIWORD(lParam)) { // if it's not zero if (hsb == hInScroll) { // If it's from the IN Scroll Bar switch (wParam) { // find out what happened... case SB_PAGEUP: // User did a PAGE UP settings.insecs -= 4; // take off 4 seconds and... case SB_LINEUP: // User did a LINE UP // take off 1 second or set to 1, whichever is greater settings.insecs = max(1, settings.insecs-1); break; case SB_PAGEDOWN: // User did a PAGE DOWN settings.insecs += 4; // add 4 seconds and... case SB_LINEDOWN: // User did a LINE DOWN // add 1 second or set to 1 minute, whichever is lesser settings.insecs = min(MAX_IN, settings.insecs+1); break; case SB_TOP: // User went to the TOP settings.insecs = 1; // set to 1 second break; case SB_BOTTOM: // User went the to BOTTOM settings.insecs = MAX_IN; // set to 1 minute break; case SB_THUMBPOSITION: // User moved... case SB_THUMBTRACK: // or is moving the THUMB BUTTON // Windows tells us how far... settings.insecs = LOWORD(lParam); default: break; } // Put the new value into a string sprintf(temp, "%4d", settings.insecs); // Display it in the box next to the Scroll Bar SetDlgItemText(hDlg, IDC_INSECS, temp); // Set the new Scroll Bar position SetScrollPos(hsb, SB_CTL, settings.insecs, TRUE); } else if (hsb == hOutScroll) { // If it's from the OUT Scroll Bar switch (wParam) { // find out what happened... case SB_PAGEUP: // User did a PAGE UP settings.outsecs -= 559; // take off 10 min and... case SB_LINEUP: // User did a LINE UP // take off 1 second or set to 1, whichever is greater settings.outsecs = max(1, settings.outsecs-1); break; case SB_PAGEDOWN: // User did a PAGE DOWN settings.outsecs += 559; // add 10 min and... case SB_LINEDOWN: // User did a LINE DOWN // add 1 second or set to 1 hour, whichever is lesser settings.outsecs = min(MAX_OUT, settings.outsecs+1); break; case SB_TOP: // User went to the TOP settings.outsecs = 1; // set to 1 second break; case SB_BOTTOM: // User went the to BOTTOM settings.outsecs = MAX_IN; // set to 1 hour break; case SB_THUMBPOSITION: // User moved... case SB_THUMBTRACK: // or is moving the THUMB BUTTON // Windows tells us how far... settings.outsecs = LOWORD(lParam); default: break; } // Put the new value into a string sprintf(temp, "%4d", settings.outsecs); // Display it in the box next to the Scroll Bar SetDlgItemText(hDlg, IDC_OUTSECS, temp); // Set the new Scroll Bar position SetScrollPos(hsb, SB_CTL, settings.outsecs, TRUE); } } return TRUE; case WM_COMMAND: // One of the Buttons got pressed switch (wParam) { // which one? case IDC_SAVE: // Save Settings SaveSettings(hDlg); // Save the Settings break; case IDCANCEL: // CANCEL settings = s; // Restore setting to what they were case IDOK: // OK EndDialog(hDlg, TRUE); // we're done return TRUE; default: break; } break; } return FALSE; // Say that we did NOT process the message } // Retrieve WIN.INI settings for Pundit void FetchSettings(void) { // Here we get each of the 6 settings values // from WIN.INI settings.insecs = GetProfileInt((LPSTR)szAppName, (LPSTR)"InSecs", settings.insecs); settings.outsecs = GetProfileInt((LPSTR)szAppName, (LPSTR)"OutSecs", settings.outsecs); settings.x = GetProfileInt((LPSTR)szAppName, (LPSTR)"X", settings.x); settings.y = GetProfileInt((LPSTR)szAppName, (LPSTR)"Y", settings.y); settings.width = GetProfileInt((LPSTR)szAppName, (LPSTR)"Width", settings.width); settings.height = GetProfileInt((LPSTR)szAppName, (LPSTR)"Height", settings.height); } // Save the Settings (from Settings Dialog) void SaveSettings(hDlg) HWND hDlg; { char buf[10]; // a string to write "numbers" into int save_size = FALSE; // flag to save Window size/position RECT rect; // boundaries of entire Window // write the IN seconds sprintf(buf, "%d", settings.insecs); WriteProfileString((LPSTR)szAppName, (LPSTR)"InSecs", (LPSTR)buf); // write the OUT seconds sprintf(buf, "%d", settings.outsecs); WriteProfileString((LPSTR)szAppName, (LPSTR)"OutSecs", (LPSTR)buf); // Ask user if we should save position and size save_size = MessageBox(hDlg, (LPSTR)"Save Current Window Position and Size?", (LPSTR)"Saving", MB_ICONQUESTION | MB_YESNO); if (save_size == IDYES) { // User answered "YES" // Ask Windows for size of entire window GetWindowRect(jkbPundit, (LPRECT)&rect); settings.x = rect.left; // X position settings.y = rect.top; // Y position settings.width = rect.right - rect.left; // Width settings.height = rect.bottom - rect.top; // Height // write the X position sprintf(buf, "%d", settings.x); WriteProfileString((LPSTR)szAppName, (LPSTR)"X", (LPSTR)buf); // write the Y position sprintf(buf, "%d", settings.y); WriteProfileString((LPSTR)szAppName, (LPSTR)"Y", (LPSTR)buf); // write the Width sprintf(buf, "%d", settings.width); WriteProfileString((LPSTR)szAppName, (LPSTR)"Width", (LPSTR)buf); // write the Height sprintf(buf, "%d", settings.height); WriteProfileString((LPSTR)szAppName, (LPSTR)"Height", (LPSTR)buf); } } // Initialize Settings Dialog info void InitSettings(hDlg) HWND hDlg; { char temp[10]; // a string to write "numbers" into s = settings; // stash the current settings (in case of CANCEL) // Write the current IN seconds in the box next to the Scroll Bar sprintf(temp, "%4d", settings.insecs); SetDlgItemText(hDlg, IDC_INSECS, temp); // Write the current OUT seconds in the box next to the Scroll Bar sprintf(temp, "%4d", settings.outsecs); SetDlgItemText(hDlg, IDC_OUTSECS, temp); // Get handles to each of the 2 Scroll Bar Controls hInScroll = GetDlgItem(hDlg, IDC_INSCROLL); hOutScroll = GetDlgItem(hDlg, IDC_OUTSCROLL); // Set the Scroll Bar Ranges SetScrollRange(hInScroll, SB_CTL, 1, MAX_IN, TRUE); SetScrollRange(hOutScroll, SB_CTL, 1, MAX_OUT, TRUE); // Set the Scroll Bar Positions SetScrollPos(hInScroll, SB_CTL, settings.insecs, TRUE); SetScrollPos(hOutScroll, SB_CTL, settings.outsecs, TRUE); }