/* * Clock * * Copyright 1998 Marcel Baur * * Clock is partially based on * - Program Manager by Ulrich Schmied * - rolex.c by Jim Peterson * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "windows.h" #include "commdlg.h" #include "main.h" #include "winclock.h" #define INITIAL_WINDOW_SIZE 200 #define TIMER_ID 1 CLOCK_GLOBALS Globals; static VOID WineLicense(HWND Wnd) { char cap[20], text[1024]; LoadString(Globals.hInstance, IDS_LICENSE, text, sizeof text); LoadString(Globals.hInstance, IDS_LICENSE_CAPTION, cap, sizeof cap); MessageBox(Wnd, text, cap, MB_ICONINFORMATION | MB_OK); } static VOID WineWarranty(HWND Wnd) { char cap[20], text[1024]; LoadString(Globals.hInstance, IDS_WARRANTY, text, sizeof text); LoadString(Globals.hInstance, IDS_WARRANTY_CAPTION, cap, sizeof cap); MessageBox(Wnd, text, cap, MB_ICONEXCLAMATION | MB_OK); } static VOID CLOCK_UpdateMenuCheckmarks(VOID) { HMENU hPropertiesMenu; hPropertiesMenu = GetSubMenu(Globals.hMainMenu, 0); if (!hPropertiesMenu) return; if(Globals.bAnalog) { /* analog clock */ CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_ANALOG, MF_CHECKED); EnableMenuItem(hPropertiesMenu, IDM_FONT, MF_GRAYED); } else { /* digital clock */ CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_DIGITAL, MF_CHECKED); EnableMenuItem(hPropertiesMenu, IDM_FONT, 0); } CheckMenuItem(hPropertiesMenu, IDM_NOTITLE, (Globals.bWithoutTitle ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hPropertiesMenu, IDM_ONTOP, (Globals.bAlwaysOnTop ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hPropertiesMenu, IDM_SECONDS, (Globals.bSeconds ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hPropertiesMenu, IDM_DATE, (Globals.bDate ? MF_CHECKED : MF_UNCHECKED)); } static VOID CLOCK_UpdateWindowCaption(VOID) { CHAR szCaption[MAX_STRING_LEN]; int chars = 0; /* Set frame caption */ if (Globals.bDate) { chars = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL, szCaption, sizeof(szCaption)); if (chars) { --chars; szCaption[chars++] = ' '; szCaption[chars++] = '-'; szCaption[chars++] = ' '; szCaption[chars] = '\0'; } } LoadString(0, IDS_CLOCK, szCaption + chars, sizeof(szCaption) - chars); SetWindowText(Globals.hMainWnd, szCaption); } /*********************************************************************** * * CLOCK_ResetTimer */ static BOOL CLOCK_ResetTimer(void) { UINT period; /* milliseconds */ KillTimer(Globals.hMainWnd, TIMER_ID); if (Globals.bSeconds) if (Globals.bAnalog) period = 50; else period = 500; else period = 1000; if (!SetTimer (Globals.hMainWnd, TIMER_ID, period, NULL)) { CHAR szApp[MAX_STRING_LEN]; LoadString(Globals.hInstance, IDS_CLOCK, szApp, sizeof(szApp)); MessageBox(0, "No available timers", szApp, MB_ICONEXCLAMATION | MB_OK); return FALSE; } return TRUE; } /*********************************************************************** * * CLOCK_ResetFont */ static VOID CLOCK_ResetFont(VOID) { HFONT newfont; HDC dc = GetDC(Globals.hMainWnd); newfont = SizeFont(dc, Globals.MaxX, Globals.MaxY, Globals.bSeconds, &Globals.logfont); if (newfont) { DeleteObject(Globals.hFont); Globals.hFont = newfont; } ReleaseDC(Globals.hMainWnd, dc); } /*********************************************************************** * * CLOCK_ChooseFont */ static VOID CLOCK_ChooseFont(VOID) { LOGFONT lf; CHOOSEFONT cf; memset(&cf, 0, sizeof(cf)); lf = Globals.logfont; cf.lStructSize = sizeof(cf); cf.hwndOwner = Globals.hMainWnd; cf.lpLogFont = &lf; cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT; if (ChooseFont(&cf)) { Globals.logfont = lf; CLOCK_ResetFont(); } } /*********************************************************************** * * CLOCK_ToggleTitle */ static VOID CLOCK_ToggleTitle(VOID) { /* Also shows/hides the menu */ LONG style = GetWindowLong(Globals.hMainWnd, GWL_STYLE); if ((Globals.bWithoutTitle = !Globals.bWithoutTitle)) { style = (style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP|WS_THICKFRAME; SetMenu(Globals.hMainWnd, 0); } else { style = (style & ~(WS_POPUP|WS_THICKFRAME)) | WS_OVERLAPPEDWINDOW; SetMenu(Globals.hMainWnd, Globals.hMainMenu); } SetWindowLong(Globals.hMainWnd, GWL_STYLE, style); SetWindowPos(Globals.hMainWnd, 0,0,0,0,0, SWP_DRAWFRAME|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER); CLOCK_UpdateMenuCheckmarks(); CLOCK_UpdateWindowCaption(); } /*********************************************************************** * * CLOCK_ToggleOnTop */ static VOID CLOCK_ToggleOnTop(VOID) { if ((Globals.bAlwaysOnTop = !Globals.bAlwaysOnTop)) { SetWindowPos(Globals.hMainWnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); } else { SetWindowPos(Globals.hMainWnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); } CLOCK_UpdateMenuCheckmarks(); } /*********************************************************************** * * CLOCK_MenuCommand * * All handling of main menu events */ static int CLOCK_MenuCommand (WPARAM wParam) { CHAR szApp[MAX_STRING_LEN]; CHAR szAppRelease[MAX_STRING_LEN]; switch (wParam) { /* switch to analog */ case IDM_ANALOG: { Globals.bAnalog = TRUE; CLOCK_UpdateMenuCheckmarks(); CLOCK_ResetTimer(); InvalidateRect(Globals.hMainWnd, NULL, FALSE); break; } /* switch to digital */ case IDM_DIGITAL: { Globals.bAnalog = FALSE; CLOCK_UpdateMenuCheckmarks(); CLOCK_ResetTimer(); CLOCK_ResetFont(); InvalidateRect(Globals.hMainWnd, NULL, FALSE); break; } /* change font */ case IDM_FONT: { CLOCK_ChooseFont(); break; } /* hide title bar */ case IDM_NOTITLE: { CLOCK_ToggleTitle(); break; } /* always on top */ case IDM_ONTOP: { CLOCK_ToggleOnTop(); break; } /* show or hide seconds */ case IDM_SECONDS: { Globals.bSeconds = !Globals.bSeconds; CLOCK_UpdateMenuCheckmarks(); CLOCK_ResetTimer(); if (!Globals.bAnalog) CLOCK_ResetFont(); InvalidateRect(Globals.hMainWnd, NULL, FALSE); break; } /* show or hide date */ case IDM_DATE: { Globals.bDate = !Globals.bDate; CLOCK_UpdateMenuCheckmarks(); CLOCK_UpdateWindowCaption(); break; } /* show license */ case IDM_LICENSE: { WineLicense(Globals.hMainWnd); break; } /* show warranties */ case IDM_NOWARRANTY: { WineWarranty(Globals.hMainWnd); break; } /* show "about" box */ case IDM_ABOUT: { LoadString(Globals.hInstance, IDS_CLOCK, szApp, sizeof(szApp)); lstrcpy(szAppRelease,szApp); ShellAbout(Globals.hMainWnd, szApp, szAppRelease, 0); break; } } return 0; } /*********************************************************************** * * CLOCK_Paint */ static VOID CLOCK_Paint(HWND hWnd) { PAINTSTRUCT ps; HDC dcMem, dc; HBITMAP bmMem, bmOld; dc = BeginPaint(hWnd, &ps); /* Use an offscreen dc to avoid flicker */ dcMem = CreateCompatibleDC(dc); bmMem = CreateCompatibleBitmap(dc, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top); bmOld = SelectObject(dcMem, bmMem); SetViewportOrgEx(dcMem, -ps.rcPaint.left, -ps.rcPaint.top, NULL); /* Erase the background */ FillRect(dcMem, &ps.rcPaint, GetStockObject(LTGRAY_BRUSH)); if(Globals.bAnalog) AnalogClock(dcMem, Globals.MaxX, Globals.MaxY, Globals.bSeconds); else DigitalClock(dcMem, Globals.MaxX, Globals.MaxY, Globals.bSeconds, Globals.hFont); /* Blit the changes to the screen */ BitBlt(dc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, dcMem, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); SelectObject(dcMem, bmOld); DeleteObject(bmMem); DeleteDC(dcMem); EndPaint(hWnd, &ps); } /*********************************************************************** * * CLOCK_WndProc */ static LRESULT WINAPI CLOCK_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { /* L button drag moves the window */ case WM_NCHITTEST: { LRESULT ret = DefWindowProc (hWnd, msg, wParam, lParam); if (ret == HTCLIENT) ret = HTCAPTION; return ret; } case WM_NCLBUTTONDBLCLK: case WM_LBUTTONDBLCLK: { CLOCK_ToggleTitle(); break; } case WM_PAINT: { CLOCK_Paint(hWnd); break; } case WM_SIZE: { Globals.MaxX = LOWORD(lParam); Globals.MaxY = HIWORD(lParam); CLOCK_ResetFont(); break; } case WM_COMMAND: { CLOCK_MenuCommand(wParam); break; } case WM_TIMER: { /* Could just invalidate what has changed, * but it doesn't really seem worth the effort */ InvalidateRect(Globals.hMainWnd, NULL, FALSE); break; } case WM_DESTROY: { PostQuitMessage (0); break; } default: return DefWindowProc (hWnd, msg, wParam, lParam); } return 0; } /*********************************************************************** * * WinMain */ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show) { MSG msg; WNDCLASS class; static const char szClassName[] = "CLClass"; /* To make sure className >= 0x10000 */ static const char szWinName[] = "Clock"; /* Setup Globals */ memset(&Globals.hFont, 0, sizeof (Globals.hFont)); Globals.bAnalog = TRUE; Globals.bSeconds = TRUE; if (!prev){ class.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; class.lpfnWndProc = CLOCK_WndProc; class.cbClsExtra = 0; class.cbWndExtra = 0; class.hInstance = hInstance; class.hIcon = LoadIcon (0, IDI_APPLICATION); class.hCursor = LoadCursor (0, IDC_ARROW); class.hbrBackground = 0; class.lpszMenuName = 0; class.lpszClassName = szClassName; } if (!RegisterClass (&class)) return FALSE; Globals.MaxX = Globals.MaxY = INITIAL_WINDOW_SIZE; Globals.hMainWnd = CreateWindow (szClassName, szWinName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Globals.MaxX, Globals.MaxY, 0, 0, hInstance, 0); if (!CLOCK_ResetTimer()) return FALSE; Globals.hMainMenu = LoadMenu(0, MAKEINTRESOURCE(MAIN_MENU)); SetMenu(Globals.hMainWnd, Globals.hMainMenu); CLOCK_UpdateMenuCheckmarks(); CLOCK_UpdateWindowCaption(); ShowWindow (Globals.hMainWnd, show); UpdateWindow (Globals.hMainWnd); while (GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } KillTimer(Globals.hMainWnd, TIMER_ID); DeleteObject(Globals.hFont); return 0; }