push 5b1efc32b5a8acb1d5b5e60584746392dd0c436e
[wine/hacks.git] / programs / clock / main.c
blob752c93bf14b8df6e9ad76defeb5ce9f66ad549c6
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 "commdlg.h"
31 #include "main.h"
32 #include "winclock.h"
34 #define INITIAL_WINDOW_SIZE 200
35 #define TIMER_ID 1
37 CLOCK_GLOBALS Globals;
39 static VOID WineLicense(HWND Wnd)
41 WCHAR cap[20], text[1024];
42 LoadStringW(Globals.hInstance, IDS_LICENSE, text, sizeof(text)/sizeof(WCHAR));
43 LoadStringW(Globals.hInstance, IDS_LICENSE_CAPTION, cap, sizeof(cap)/sizeof(WCHAR));
44 MessageBoxW(Wnd, text, cap, MB_ICONINFORMATION | MB_OK);
47 static VOID WineWarranty(HWND Wnd)
49 WCHAR cap[20], text[1024];
50 LoadStringW(Globals.hInstance, IDS_WARRANTY, text, sizeof(text)/sizeof(WCHAR));
51 LoadStringW(Globals.hInstance, IDS_WARRANTY_CAPTION, cap, sizeof(cap)/sizeof(WCHAR));
52 MessageBoxW(Wnd, text, cap, MB_ICONEXCLAMATION | MB_OK);
55 static VOID CLOCK_UpdateMenuCheckmarks(VOID)
57 HMENU hPropertiesMenu;
58 hPropertiesMenu = GetSubMenu(Globals.hMainMenu, 0);
59 if (!hPropertiesMenu)
60 return;
62 if(Globals.bAnalog) {
64 /* analog clock */
65 CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_ANALOG, MF_CHECKED);
66 EnableMenuItem(hPropertiesMenu, IDM_FONT, MF_GRAYED);
68 else
70 /* digital clock */
71 CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_DIGITAL, MF_CHECKED);
72 EnableMenuItem(hPropertiesMenu, IDM_FONT, 0);
75 CheckMenuItem(hPropertiesMenu, IDM_NOTITLE, (Globals.bWithoutTitle ? MF_CHECKED : MF_UNCHECKED));
77 CheckMenuItem(hPropertiesMenu, IDM_ONTOP, (Globals.bAlwaysOnTop ? MF_CHECKED : MF_UNCHECKED));
78 CheckMenuItem(hPropertiesMenu, IDM_SECONDS, (Globals.bSeconds ? MF_CHECKED : MF_UNCHECKED));
79 CheckMenuItem(hPropertiesMenu, IDM_DATE, (Globals.bDate ? MF_CHECKED : MF_UNCHECKED));
82 static VOID CLOCK_UpdateWindowCaption(VOID)
84 WCHAR szCaption[MAX_STRING_LEN];
85 int chars = 0;
87 /* Set frame caption */
88 if (Globals.bDate) {
89 chars = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL,
90 szCaption, sizeof(szCaption)/sizeof(WCHAR));
91 if (chars) {
92 --chars;
93 szCaption[chars++] = ' ';
94 szCaption[chars++] = '-';
95 szCaption[chars++] = ' ';
96 szCaption[chars] = '\0';
99 LoadStringW(0, IDS_CLOCK, szCaption + chars, MAX_STRING_LEN - chars);
100 SetWindowTextW(Globals.hMainWnd, szCaption);
103 /***********************************************************************
105 * CLOCK_ResetTimer
107 static BOOL CLOCK_ResetTimer(void)
109 UINT period; /* milliseconds */
111 KillTimer(Globals.hMainWnd, TIMER_ID);
113 if (Globals.bSeconds)
114 if (Globals.bAnalog)
115 period = 50;
116 else
117 period = 500;
118 else
119 period = 1000;
121 if (!SetTimer (Globals.hMainWnd, TIMER_ID, period, NULL)) {
122 static const WCHAR notimersW[] = {'N','o',' ','a','v','a','i','l','a','b','l','e',' ','t','i','m','e','r','s',0};
123 WCHAR szApp[MAX_STRING_LEN];
124 LoadStringW(Globals.hInstance, IDS_CLOCK, szApp, MAX_STRING_LEN);
125 MessageBoxW(0, notimersW, szApp, MB_ICONEXCLAMATION | MB_OK);
126 return FALSE;
128 return TRUE;
131 /***********************************************************************
133 * CLOCK_ResetFont
135 static VOID CLOCK_ResetFont(VOID)
137 HFONT newfont;
138 HDC dc = GetDC(Globals.hMainWnd);
139 newfont = SizeFont(dc, Globals.MaxX, Globals.MaxY, Globals.bSeconds, &Globals.logfont);
140 if (newfont) {
141 DeleteObject(Globals.hFont);
142 Globals.hFont = newfont;
145 ReleaseDC(Globals.hMainWnd, dc);
149 /***********************************************************************
151 * CLOCK_ChooseFont
153 static VOID CLOCK_ChooseFont(VOID)
155 LOGFONTW lf;
156 CHOOSEFONTW cf;
157 memset(&cf, 0, sizeof(cf));
158 lf = Globals.logfont;
159 cf.lStructSize = sizeof(cf);
160 cf.hwndOwner = Globals.hMainWnd;
161 cf.lpLogFont = &lf;
162 cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
163 if (ChooseFontW(&cf)) {
164 Globals.logfont = lf;
165 CLOCK_ResetFont();
169 /***********************************************************************
171 * CLOCK_ToggleTitle
173 static VOID CLOCK_ToggleTitle(VOID)
175 /* Also shows/hides the menu */
176 LONG style = GetWindowLongW(Globals.hMainWnd, GWL_STYLE);
177 if ((Globals.bWithoutTitle = !Globals.bWithoutTitle)) {
178 style = (style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP|WS_THICKFRAME;
179 SetMenu(Globals.hMainWnd, 0);
181 else {
182 style = (style & ~(WS_POPUP|WS_THICKFRAME)) | WS_OVERLAPPEDWINDOW;
183 SetMenu(Globals.hMainWnd, Globals.hMainMenu);
184 SetWindowRgn(Globals.hMainWnd, 0, TRUE);
186 SetWindowLongW(Globals.hMainWnd, GWL_STYLE, style);
187 SetWindowPos(Globals.hMainWnd, 0,0,0,0,0,
188 SWP_DRAWFRAME|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER);
190 CLOCK_UpdateMenuCheckmarks();
191 CLOCK_UpdateWindowCaption();
194 /***********************************************************************
196 * CLOCK_ToggleOnTop
198 static VOID CLOCK_ToggleOnTop(VOID)
200 if ((Globals.bAlwaysOnTop = !Globals.bAlwaysOnTop)) {
201 SetWindowPos(Globals.hMainWnd, HWND_TOPMOST, 0,0,0,0,
202 SWP_NOMOVE|SWP_NOSIZE);
204 else {
205 SetWindowPos(Globals.hMainWnd, HWND_NOTOPMOST, 0,0,0,0,
206 SWP_NOMOVE|SWP_NOSIZE);
208 CLOCK_UpdateMenuCheckmarks();
210 /***********************************************************************
212 * CLOCK_MenuCommand
214 * All handling of main menu events
217 static int CLOCK_MenuCommand (WPARAM wParam)
219 WCHAR szApp[MAX_STRING_LEN];
220 WCHAR szAppRelease[MAX_STRING_LEN];
221 switch (wParam) {
222 /* switch to analog */
223 case IDM_ANALOG: {
224 Globals.bAnalog = TRUE;
225 CLOCK_UpdateMenuCheckmarks();
226 CLOCK_ResetTimer();
227 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
228 break;
230 /* switch to digital */
231 case IDM_DIGITAL: {
232 Globals.bAnalog = FALSE;
233 CLOCK_UpdateMenuCheckmarks();
234 CLOCK_ResetTimer();
235 CLOCK_ResetFont();
236 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
237 break;
239 /* change font */
240 case IDM_FONT: {
241 CLOCK_ChooseFont();
242 break;
244 /* hide title bar */
245 case IDM_NOTITLE: {
246 CLOCK_ToggleTitle();
247 break;
249 /* always on top */
250 case IDM_ONTOP: {
251 CLOCK_ToggleOnTop();
252 break;
254 /* show or hide seconds */
255 case IDM_SECONDS: {
256 Globals.bSeconds = !Globals.bSeconds;
257 CLOCK_UpdateMenuCheckmarks();
258 CLOCK_ResetTimer();
259 if (!Globals.bAnalog)
260 CLOCK_ResetFont();
261 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
262 break;
264 /* show or hide date */
265 case IDM_DATE: {
266 Globals.bDate = !Globals.bDate;
267 CLOCK_UpdateMenuCheckmarks();
268 CLOCK_UpdateWindowCaption();
269 break;
271 /* show license */
272 case IDM_LICENSE: {
273 WineLicense(Globals.hMainWnd);
274 break;
276 /* show warranties */
277 case IDM_NOWARRANTY: {
278 WineWarranty(Globals.hMainWnd);
279 break;
281 /* show "about" box */
282 case IDM_ABOUT: {
283 LoadStringW(Globals.hInstance, IDS_CLOCK, szApp, sizeof(szApp)/sizeof(WCHAR));
284 lstrcpyW(szAppRelease,szApp);
285 ShellAboutW(Globals.hMainWnd, szApp, szAppRelease, 0);
286 break;
289 return 0;
292 /***********************************************************************
294 * CLOCK_Paint
296 static VOID CLOCK_Paint(HWND hWnd)
298 PAINTSTRUCT ps;
299 HDC dcMem, dc;
300 HBITMAP bmMem, bmOld;
302 dc = BeginPaint(hWnd, &ps);
304 /* Use an offscreen dc to avoid flicker */
305 dcMem = CreateCompatibleDC(dc);
306 bmMem = CreateCompatibleBitmap(dc, ps.rcPaint.right - ps.rcPaint.left,
307 ps.rcPaint.bottom - ps.rcPaint.top);
309 bmOld = SelectObject(dcMem, bmMem);
311 SetViewportOrgEx(dcMem, -ps.rcPaint.left, -ps.rcPaint.top, NULL);
312 /* Erase the background */
313 FillRect(dcMem, &ps.rcPaint, GetSysColorBrush(COLOR_3DFACE));
315 if(Globals.bAnalog)
316 AnalogClock(dcMem, Globals.MaxX, Globals.MaxY, Globals.bSeconds, Globals.bWithoutTitle);
317 else
318 DigitalClock(dcMem, Globals.MaxX, Globals.MaxY, Globals.bSeconds, Globals.hFont);
320 /* Blit the changes to the screen */
321 BitBlt(dc,
322 ps.rcPaint.left, ps.rcPaint.top,
323 ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
324 dcMem,
325 ps.rcPaint.left, ps.rcPaint.top,
326 SRCCOPY);
328 SelectObject(dcMem, bmOld);
329 DeleteObject(bmMem);
330 DeleteDC(dcMem);
332 EndPaint(hWnd, &ps);
335 /***********************************************************************
337 * CLOCK_WndProc
340 static LRESULT WINAPI CLOCK_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
342 switch (msg) {
343 /* L button drag moves the window */
344 case WM_NCHITTEST: {
345 LRESULT ret = DefWindowProcW(hWnd, msg, wParam, lParam);
346 if (ret == HTCLIENT)
347 ret = HTCAPTION;
348 return ret;
351 case WM_NCLBUTTONDBLCLK:
352 case WM_LBUTTONDBLCLK: {
353 CLOCK_ToggleTitle();
354 break;
357 case WM_PAINT: {
358 CLOCK_Paint(hWnd);
359 break;
363 case WM_SIZE: {
364 Globals.MaxX = LOWORD(lParam);
365 Globals.MaxY = HIWORD(lParam);
366 if (Globals.bAnalog && Globals.bWithoutTitle)
368 RECT rect;
369 INT diameter = min( Globals.MaxX, Globals.MaxY );
370 HRGN hrgn = CreateEllipticRgn( (Globals.MaxX - diameter) / 2,
371 (Globals.MaxY - diameter) / 2,
372 (Globals.MaxX + diameter) / 2,
373 (Globals.MaxY + diameter) / 2 );
374 GetWindowRect( hWnd, &rect );
375 MapWindowPoints( 0, hWnd, (LPPOINT)&rect, 2 );
376 OffsetRgn( hrgn, -rect.left, -rect.top );
377 SetWindowRgn( Globals.hMainWnd, hrgn, TRUE );
379 CLOCK_ResetFont();
380 break;
383 case WM_COMMAND: {
384 CLOCK_MenuCommand(wParam);
385 break;
388 case WM_TIMER: {
389 /* Could just invalidate what has changed,
390 * but it doesn't really seem worth the effort
392 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
393 break;
396 case WM_DESTROY: {
397 PostQuitMessage (0);
398 break;
401 default:
402 return DefWindowProcW(hWnd, msg, wParam, lParam);
404 return 0;
408 /***********************************************************************
410 * WinMain
413 int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
415 MSG msg;
416 WNDCLASSW class;
418 static const WCHAR szClassName[] = {'C','L','C','l','a','s','s',0};
419 static const WCHAR szWinName[] = {'C','l','o','c','k',0};
421 /* Setup Globals */
422 memset(&Globals.hFont, 0, sizeof (Globals.hFont));
423 Globals.bAnalog = TRUE;
424 Globals.bSeconds = TRUE;
426 if (!prev){
427 class.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
428 class.lpfnWndProc = CLOCK_WndProc;
429 class.cbClsExtra = 0;
430 class.cbWndExtra = 0;
431 class.hInstance = hInstance;
432 class.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
433 class.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
434 class.hbrBackground = 0;
435 class.lpszMenuName = 0;
436 class.lpszClassName = szClassName;
439 if (!RegisterClassW(&class)) return FALSE;
441 Globals.MaxX = Globals.MaxY = INITIAL_WINDOW_SIZE;
442 Globals.hMainWnd = CreateWindowW(szClassName, szWinName, WS_OVERLAPPEDWINDOW,
443 CW_USEDEFAULT, CW_USEDEFAULT,
444 Globals.MaxX, Globals.MaxY, 0,
445 0, hInstance, 0);
447 if (!CLOCK_ResetTimer())
448 return FALSE;
450 Globals.hMainMenu = LoadMenuW(0, MAKEINTRESOURCEW(MAIN_MENU));
451 SetMenu(Globals.hMainWnd, Globals.hMainMenu);
452 CLOCK_UpdateMenuCheckmarks();
453 CLOCK_UpdateWindowCaption();
455 ShowWindow (Globals.hMainWnd, show);
456 UpdateWindow (Globals.hMainWnd);
458 while (GetMessageW(&msg, 0, 0, 0)) {
459 TranslateMessage(&msg);
460 DispatchMessageW(&msg);
463 KillTimer(Globals.hMainWnd, TIMER_ID);
464 DeleteObject(Globals.hFont);
466 return 0;