wineoss: Fix missing break statement.
[wine.git] / programs / clock / main.c
blobe64e66dffe631b84ac1c1858fc87da1e41748b9d
1 /*
2 * Clock
4 * Copyright 1998 Marcel Baur <mbaur@g26.ethz.ch>
6 * Clock is partially based on
7 * - Program Manager by Ulrich Schmied
8 * - rolex.c by Jim Peterson
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <stdio.h>
28 #include "windows.h"
29 #include "commctrl.h"
30 #include "commdlg.h"
31 #include "shellapi.h"
33 #include "main.h"
34 #include "winclock.h"
36 #define INITIAL_WINDOW_SIZE 200
37 #define TIMER_ID 1
39 CLOCK_GLOBALS Globals;
41 static VOID CLOCK_UpdateMenuCheckmarks(VOID)
43 HMENU hPropertiesMenu;
44 hPropertiesMenu = GetSubMenu(Globals.hMainMenu, 0);
45 if (!hPropertiesMenu)
46 return;
48 if(Globals.bAnalog) {
50 /* analog clock */
51 CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_ANALOG, MF_CHECKED);
52 EnableMenuItem(hPropertiesMenu, IDM_FONT, MF_GRAYED);
54 else
56 /* digital clock */
57 CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_DIGITAL, MF_CHECKED);
58 EnableMenuItem(hPropertiesMenu, IDM_FONT, 0);
61 CheckMenuItem(hPropertiesMenu, IDM_NOTITLE, (Globals.bWithoutTitle ? MF_CHECKED : MF_UNCHECKED));
63 CheckMenuItem(hPropertiesMenu, IDM_ONTOP, (Globals.bAlwaysOnTop ? MF_CHECKED : MF_UNCHECKED));
64 CheckMenuItem(hPropertiesMenu, IDM_SECONDS, (Globals.bSeconds ? MF_CHECKED : MF_UNCHECKED));
65 CheckMenuItem(hPropertiesMenu, IDM_DATE, (Globals.bDate ? MF_CHECKED : MF_UNCHECKED));
68 static VOID CLOCK_UpdateWindowCaption(VOID)
70 WCHAR szCaption[MAX_STRING_LEN];
71 int chars = 0;
73 /* Set frame caption */
74 if (Globals.bDate) {
75 chars = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL,
76 szCaption, ARRAY_SIZE(szCaption));
77 if (chars) {
78 --chars;
79 szCaption[chars++] = ' ';
80 szCaption[chars++] = '-';
81 szCaption[chars++] = ' ';
82 szCaption[chars] = '\0';
85 LoadStringW(0, IDS_CLOCK, szCaption + chars, MAX_STRING_LEN - chars);
86 SetWindowTextW(Globals.hMainWnd, szCaption);
89 /***********************************************************************
91 * CLOCK_ResetTimer
93 static BOOL CLOCK_ResetTimer(void)
95 UINT period; /* milliseconds */
97 KillTimer(Globals.hMainWnd, TIMER_ID);
99 if (Globals.bSeconds)
100 if (Globals.bAnalog)
101 period = 50;
102 else
103 period = 500;
104 else
105 period = 1000;
107 if (!SetTimer (Globals.hMainWnd, TIMER_ID, period, NULL)) {
108 WCHAR szApp[MAX_STRING_LEN];
109 LoadStringW(Globals.hInstance, IDS_CLOCK, szApp, MAX_STRING_LEN);
110 MessageBoxW(0, L"No available timers", szApp, MB_ICONEXCLAMATION | MB_OK);
111 return FALSE;
113 return TRUE;
116 /***********************************************************************
118 * CLOCK_ResetFont
120 static VOID CLOCK_ResetFont(VOID)
122 HFONT newfont;
123 HDC dc = GetDC(Globals.hMainWnd);
124 newfont = SizeFont(dc, Globals.MaxX, Globals.MaxY, Globals.bSeconds, &Globals.logfont);
125 if (newfont) {
126 DeleteObject(Globals.hFont);
127 Globals.hFont = newfont;
130 ReleaseDC(Globals.hMainWnd, dc);
134 /***********************************************************************
136 * CLOCK_ChooseFont
138 static VOID CLOCK_ChooseFont(VOID)
140 LOGFONTW lf;
141 CHOOSEFONTW cf;
142 memset(&cf, 0, sizeof(cf));
143 lf = Globals.logfont;
144 cf.lStructSize = sizeof(cf);
145 cf.hwndOwner = Globals.hMainWnd;
146 cf.lpLogFont = &lf;
147 cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_NOVERTFONTS;
148 if (ChooseFontW(&cf)) {
149 Globals.logfont = lf;
150 CLOCK_ResetFont();
154 /***********************************************************************
156 * CLOCK_ToggleTitle
158 static VOID CLOCK_ToggleTitle(VOID)
160 /* Also shows/hides the menu */
161 LONG style = GetWindowLongW(Globals.hMainWnd, GWL_STYLE);
162 if ((Globals.bWithoutTitle = !Globals.bWithoutTitle)) {
163 style = (style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP|WS_THICKFRAME;
164 SetMenu(Globals.hMainWnd, 0);
166 else {
167 style = (style & ~(WS_POPUP|WS_THICKFRAME)) | WS_OVERLAPPEDWINDOW;
168 SetMenu(Globals.hMainWnd, Globals.hMainMenu);
169 SetWindowRgn(Globals.hMainWnd, 0, TRUE);
171 SetWindowLongW(Globals.hMainWnd, GWL_STYLE, style);
172 SetWindowPos(Globals.hMainWnd, 0,0,0,0,0,
173 SWP_DRAWFRAME|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER);
175 CLOCK_UpdateMenuCheckmarks();
176 CLOCK_UpdateWindowCaption();
179 /***********************************************************************
181 * CLOCK_ToggleOnTop
183 static VOID CLOCK_ToggleOnTop(VOID)
185 if ((Globals.bAlwaysOnTop = !Globals.bAlwaysOnTop)) {
186 SetWindowPos(Globals.hMainWnd, HWND_TOPMOST, 0,0,0,0,
187 SWP_NOMOVE|SWP_NOSIZE);
189 else {
190 SetWindowPos(Globals.hMainWnd, HWND_NOTOPMOST, 0,0,0,0,
191 SWP_NOMOVE|SWP_NOSIZE);
193 CLOCK_UpdateMenuCheckmarks();
195 /***********************************************************************
197 * CLOCK_MenuCommand
199 * All handling of main menu events
202 static int CLOCK_MenuCommand (WPARAM wParam)
204 WCHAR szApp[MAX_STRING_LEN];
205 WCHAR szAppRelease[MAX_STRING_LEN];
206 switch (wParam) {
207 /* switch to analog */
208 case IDM_ANALOG: {
209 Globals.bAnalog = TRUE;
210 CLOCK_UpdateMenuCheckmarks();
211 CLOCK_ResetTimer();
212 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
213 break;
215 /* switch to digital */
216 case IDM_DIGITAL: {
217 Globals.bAnalog = FALSE;
218 CLOCK_UpdateMenuCheckmarks();
219 CLOCK_ResetTimer();
220 CLOCK_ResetFont();
221 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
222 break;
224 /* change font */
225 case IDM_FONT: {
226 CLOCK_ChooseFont();
227 break;
229 /* hide title bar */
230 case IDM_NOTITLE: {
231 CLOCK_ToggleTitle();
232 break;
234 /* always on top */
235 case IDM_ONTOP: {
236 CLOCK_ToggleOnTop();
237 break;
239 /* show or hide seconds */
240 case IDM_SECONDS: {
241 Globals.bSeconds = !Globals.bSeconds;
242 CLOCK_UpdateMenuCheckmarks();
243 CLOCK_ResetTimer();
244 if (!Globals.bAnalog)
245 CLOCK_ResetFont();
246 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
247 break;
249 /* show or hide date */
250 case IDM_DATE: {
251 Globals.bDate = !Globals.bDate;
252 CLOCK_UpdateMenuCheckmarks();
253 CLOCK_UpdateWindowCaption();
254 break;
256 /* show "about" box */
257 case IDM_ABOUT: {
258 LoadStringW(Globals.hInstance, IDS_CLOCK, szApp, ARRAY_SIZE(szApp));
259 lstrcpyW(szAppRelease,szApp);
260 ShellAboutW(Globals.hMainWnd, szApp, szAppRelease, 0);
261 break;
264 return 0;
267 /***********************************************************************
269 * CLOCK_Paint
271 static VOID CLOCK_Paint(HWND hWnd)
273 PAINTSTRUCT ps;
274 HDC dcMem, dc;
275 HBITMAP bmMem, bmOld;
277 dc = BeginPaint(hWnd, &ps);
279 /* Use an offscreen dc to avoid flicker */
280 dcMem = CreateCompatibleDC(dc);
281 bmMem = CreateCompatibleBitmap(dc, ps.rcPaint.right - ps.rcPaint.left,
282 ps.rcPaint.bottom - ps.rcPaint.top);
284 bmOld = SelectObject(dcMem, bmMem);
286 SetViewportOrgEx(dcMem, -ps.rcPaint.left, -ps.rcPaint.top, NULL);
287 /* Erase the background */
288 FillRect(dcMem, &ps.rcPaint, GetSysColorBrush(COLOR_3DFACE));
290 if(Globals.bAnalog)
291 AnalogClock(dcMem, Globals.MaxX, Globals.MaxY, Globals.bSeconds, Globals.bWithoutTitle);
292 else
293 DigitalClock(dcMem, Globals.MaxX, Globals.MaxY, Globals.bSeconds, Globals.hFont);
295 /* Blit the changes to the screen */
296 BitBlt(dc,
297 ps.rcPaint.left, ps.rcPaint.top,
298 ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
299 dcMem,
300 ps.rcPaint.left, ps.rcPaint.top,
301 SRCCOPY);
303 SelectObject(dcMem, bmOld);
304 DeleteObject(bmMem);
305 DeleteDC(dcMem);
307 EndPaint(hWnd, &ps);
310 /***********************************************************************
312 * CLOCK_WndProc
315 static LRESULT WINAPI CLOCK_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
317 switch (msg) {
318 /* L button drag moves the window */
319 case WM_NCHITTEST: {
320 LRESULT ret = DefWindowProcW(hWnd, msg, wParam, lParam);
321 if (ret == HTCLIENT)
322 ret = HTCAPTION;
323 return ret;
326 case WM_NCLBUTTONDBLCLK:
327 case WM_LBUTTONDBLCLK: {
328 CLOCK_ToggleTitle();
329 break;
332 case WM_PAINT: {
333 CLOCK_Paint(hWnd);
334 break;
338 case WM_SIZE: {
339 Globals.MaxX = LOWORD(lParam);
340 Globals.MaxY = HIWORD(lParam);
341 if (Globals.bAnalog && Globals.bWithoutTitle)
343 RECT rect;
344 INT diameter = min( Globals.MaxX, Globals.MaxY );
345 HRGN hrgn = CreateEllipticRgn( (Globals.MaxX - diameter) / 2,
346 (Globals.MaxY - diameter) / 2,
347 (Globals.MaxX + diameter) / 2,
348 (Globals.MaxY + diameter) / 2 );
349 GetWindowRect( hWnd, &rect );
350 MapWindowPoints( 0, hWnd, (LPPOINT)&rect, 2 );
351 OffsetRgn( hrgn, -rect.left, -rect.top );
352 SetWindowRgn( Globals.hMainWnd, hrgn, TRUE );
354 CLOCK_ResetFont();
355 break;
358 case WM_COMMAND: {
359 CLOCK_MenuCommand(wParam);
360 break;
363 case WM_TIMER: {
364 /* Could just invalidate what has changed,
365 * but it doesn't really seem worth the effort
367 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
368 break;
371 case WM_DESTROY: {
372 PostQuitMessage (0);
373 break;
376 default:
377 return DefWindowProcW(hWnd, msg, wParam, lParam);
379 return 0;
383 /***********************************************************************
385 * WinMain
388 int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
390 MSG msg;
391 WNDCLASSW class;
393 InitCommonControls();
395 /* Setup Globals */
396 memset(&Globals.hFont, 0, sizeof (Globals.hFont));
397 Globals.bAnalog = TRUE;
398 Globals.bSeconds = TRUE;
400 if (!prev){
401 class.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
402 class.lpfnWndProc = CLOCK_WndProc;
403 class.cbClsExtra = 0;
404 class.cbWndExtra = 0;
405 class.hInstance = hInstance;
406 class.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
407 class.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
408 class.hbrBackground = 0;
409 class.lpszMenuName = 0;
410 class.lpszClassName = L"CLClass";
413 if (!RegisterClassW(&class)) return FALSE;
415 Globals.MaxX = Globals.MaxY = INITIAL_WINDOW_SIZE;
416 Globals.hMainWnd = CreateWindowW(L"CLClass", L"Clock", WS_OVERLAPPEDWINDOW,
417 CW_USEDEFAULT, CW_USEDEFAULT,
418 Globals.MaxX, Globals.MaxY, 0,
419 0, hInstance, 0);
421 if (!CLOCK_ResetTimer())
422 return FALSE;
424 Globals.hMainMenu = LoadMenuW(0, MAKEINTRESOURCEW(MAIN_MENU));
425 SetMenu(Globals.hMainWnd, Globals.hMainMenu);
426 CLOCK_UpdateMenuCheckmarks();
427 CLOCK_UpdateWindowCaption();
429 ShowWindow (Globals.hMainWnd, show);
430 UpdateWindow (Globals.hMainWnd);
432 while (GetMessageW(&msg, 0, 0, 0)) {
433 TranslateMessage(&msg);
434 DispatchMessageW(&msg);
437 KillTimer(Globals.hMainWnd, TIMER_ID);
438 DeleteObject(Globals.hFont);
440 return 0;