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
35 #define INITIAL_WINDOW_SIZE 200
38 CLOCK_GLOBALS Globals
;
40 static VOID
CLOCK_UpdateMenuCheckmarks(VOID
)
42 HMENU hPropertiesMenu
;
43 hPropertiesMenu
= GetSubMenu(Globals
.hMainMenu
, 0);
50 CheckMenuRadioItem(hPropertiesMenu
, IDM_ANALOG
, IDM_DIGITAL
, IDM_ANALOG
, MF_CHECKED
);
51 EnableMenuItem(hPropertiesMenu
, IDM_FONT
, MF_GRAYED
);
56 CheckMenuRadioItem(hPropertiesMenu
, IDM_ANALOG
, IDM_DIGITAL
, IDM_DIGITAL
, MF_CHECKED
);
57 EnableMenuItem(hPropertiesMenu
, IDM_FONT
, 0);
60 CheckMenuItem(hPropertiesMenu
, IDM_NOTITLE
, (Globals
.bWithoutTitle
? MF_CHECKED
: MF_UNCHECKED
));
62 CheckMenuItem(hPropertiesMenu
, IDM_ONTOP
, (Globals
.bAlwaysOnTop
? MF_CHECKED
: MF_UNCHECKED
));
63 CheckMenuItem(hPropertiesMenu
, IDM_SECONDS
, (Globals
.bSeconds
? MF_CHECKED
: MF_UNCHECKED
));
64 CheckMenuItem(hPropertiesMenu
, IDM_DATE
, (Globals
.bDate
? MF_CHECKED
: MF_UNCHECKED
));
67 static VOID
CLOCK_UpdateWindowCaption(VOID
)
69 WCHAR szCaption
[MAX_STRING_LEN
];
72 /* Set frame caption */
74 chars
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, NULL
, NULL
,
75 szCaption
, sizeof(szCaption
)/sizeof(WCHAR
));
78 szCaption
[chars
++] = ' ';
79 szCaption
[chars
++] = '-';
80 szCaption
[chars
++] = ' ';
81 szCaption
[chars
] = '\0';
84 LoadStringW(0, IDS_CLOCK
, szCaption
+ chars
, MAX_STRING_LEN
- chars
);
85 SetWindowTextW(Globals
.hMainWnd
, szCaption
);
88 /***********************************************************************
92 static BOOL
CLOCK_ResetTimer(void)
94 UINT period
; /* milliseconds */
96 KillTimer(Globals
.hMainWnd
, TIMER_ID
);
106 if (!SetTimer (Globals
.hMainWnd
, TIMER_ID
, period
, NULL
)) {
107 static const WCHAR notimersW
[] = {'N','o',' ','a','v','a','i','l','a','b','l','e',' ','t','i','m','e','r','s',0};
108 WCHAR szApp
[MAX_STRING_LEN
];
109 LoadStringW(Globals
.hInstance
, IDS_CLOCK
, szApp
, MAX_STRING_LEN
);
110 MessageBoxW(0, notimersW
, szApp
, MB_ICONEXCLAMATION
| MB_OK
);
116 /***********************************************************************
120 static VOID
CLOCK_ResetFont(VOID
)
123 HDC dc
= GetDC(Globals
.hMainWnd
);
124 newfont
= SizeFont(dc
, Globals
.MaxX
, Globals
.MaxY
, Globals
.bSeconds
, &Globals
.logfont
);
126 DeleteObject(Globals
.hFont
);
127 Globals
.hFont
= newfont
;
130 ReleaseDC(Globals
.hMainWnd
, dc
);
134 /***********************************************************************
138 static VOID
CLOCK_ChooseFont(VOID
)
142 memset(&cf
, 0, sizeof(cf
));
143 lf
= Globals
.logfont
;
144 cf
.lStructSize
= sizeof(cf
);
145 cf
.hwndOwner
= Globals
.hMainWnd
;
147 cf
.Flags
= CF_SCREENFONTS
| CF_INITTOLOGFONTSTRUCT
| CF_NOVERTFONTS
;
148 if (ChooseFontW(&cf
)) {
149 Globals
.logfont
= lf
;
154 /***********************************************************************
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);
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 /***********************************************************************
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
);
190 SetWindowPos(Globals
.hMainWnd
, HWND_NOTOPMOST
, 0,0,0,0,
191 SWP_NOMOVE
|SWP_NOSIZE
);
193 CLOCK_UpdateMenuCheckmarks();
195 /***********************************************************************
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
];
207 /* switch to analog */
209 Globals
.bAnalog
= TRUE
;
210 CLOCK_UpdateMenuCheckmarks();
212 InvalidateRect(Globals
.hMainWnd
, NULL
, FALSE
);
215 /* switch to digital */
217 Globals
.bAnalog
= FALSE
;
218 CLOCK_UpdateMenuCheckmarks();
221 InvalidateRect(Globals
.hMainWnd
, NULL
, FALSE
);
239 /* show or hide seconds */
241 Globals
.bSeconds
= !Globals
.bSeconds
;
242 CLOCK_UpdateMenuCheckmarks();
244 if (!Globals
.bAnalog
)
246 InvalidateRect(Globals
.hMainWnd
, NULL
, FALSE
);
249 /* show or hide date */
251 Globals
.bDate
= !Globals
.bDate
;
252 CLOCK_UpdateMenuCheckmarks();
253 CLOCK_UpdateWindowCaption();
256 /* show "about" box */
258 LoadStringW(Globals
.hInstance
, IDS_CLOCK
, szApp
, sizeof(szApp
)/sizeof(WCHAR
));
259 lstrcpyW(szAppRelease
,szApp
);
260 ShellAboutW(Globals
.hMainWnd
, szApp
, szAppRelease
, 0);
267 /***********************************************************************
271 static VOID
CLOCK_Paint(HWND hWnd
)
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
));
291 AnalogClock(dcMem
, Globals
.MaxX
, Globals
.MaxY
, Globals
.bSeconds
, Globals
.bWithoutTitle
);
293 DigitalClock(dcMem
, Globals
.MaxX
, Globals
.MaxY
, Globals
.bSeconds
, Globals
.hFont
);
295 /* Blit the changes to the screen */
297 ps
.rcPaint
.left
, ps
.rcPaint
.top
,
298 ps
.rcPaint
.right
- ps
.rcPaint
.left
, ps
.rcPaint
.bottom
- ps
.rcPaint
.top
,
300 ps
.rcPaint
.left
, ps
.rcPaint
.top
,
303 SelectObject(dcMem
, bmOld
);
310 /***********************************************************************
315 static LRESULT WINAPI
CLOCK_WndProc (HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
318 /* L button drag moves the window */
320 LRESULT ret
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
326 case WM_NCLBUTTONDBLCLK
:
327 case WM_LBUTTONDBLCLK
: {
339 Globals
.MaxX
= LOWORD(lParam
);
340 Globals
.MaxY
= HIWORD(lParam
);
341 if (Globals
.bAnalog
&& Globals
.bWithoutTitle
)
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
);
359 CLOCK_MenuCommand(wParam
);
364 /* Could just invalidate what has changed,
365 * but it doesn't really seem worth the effort
367 InvalidateRect(Globals
.hMainWnd
, NULL
, FALSE
);
377 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
383 /***********************************************************************
388 int PASCAL
WinMain (HINSTANCE hInstance
, HINSTANCE prev
, LPSTR cmdline
, int show
)
393 static const WCHAR szClassName
[] = {'C','L','C','l','a','s','s',0};
394 static const WCHAR szWinName
[] = {'C','l','o','c','k',0};
397 memset(&Globals
.hFont
, 0, sizeof (Globals
.hFont
));
398 Globals
.bAnalog
= TRUE
;
399 Globals
.bSeconds
= TRUE
;
402 class.style
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
403 class.lpfnWndProc
= CLOCK_WndProc
;
404 class.cbClsExtra
= 0;
405 class.cbWndExtra
= 0;
406 class.hInstance
= hInstance
;
407 class.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
408 class.hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
409 class.hbrBackground
= 0;
410 class.lpszMenuName
= 0;
411 class.lpszClassName
= szClassName
;
414 if (!RegisterClassW(&class)) return FALSE
;
416 Globals
.MaxX
= Globals
.MaxY
= INITIAL_WINDOW_SIZE
;
417 Globals
.hMainWnd
= CreateWindowW(szClassName
, szWinName
, WS_OVERLAPPEDWINDOW
,
418 CW_USEDEFAULT
, CW_USEDEFAULT
,
419 Globals
.MaxX
, Globals
.MaxY
, 0,
422 if (!CLOCK_ResetTimer())
425 Globals
.hMainMenu
= LoadMenuW(0, MAKEINTRESOURCEW(MAIN_MENU
));
426 SetMenu(Globals
.hMainWnd
, Globals
.hMainMenu
);
427 CLOCK_UpdateMenuCheckmarks();
428 CLOCK_UpdateWindowCaption();
430 ShowWindow (Globals
.hMainWnd
, show
);
431 UpdateWindow (Globals
.hMainWnd
);
433 while (GetMessageW(&msg
, 0, 0, 0)) {
434 TranslateMessage(&msg
);
435 DispatchMessageW(&msg
);
438 KillTimer(Globals
.hMainWnd
, TIMER_ID
);
439 DeleteObject(Globals
.hFont
);