oledb32: Implement GetConversionSize DBTYPE_WSTR->DBTYPE_WSTR.
[wine] / programs / clock / main.c
1 /*
2  * Clock
3  *
4  * Copyright 1998 Marcel Baur <mbaur@g26.ethz.ch>
5  *
6  * Clock is partially based on
7  * - Program Manager by Ulrich Schmied
8  * - rolex.c by Jim Peterson
9  *
10  *
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.
15  *
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.
20  *
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
24  */
25
26 #include <stdio.h>
27
28 #include "windows.h"
29 #include "commdlg.h"
30 #include "shellapi.h"
31
32 #include "main.h"
33 #include "winclock.h"
34
35 #define INITIAL_WINDOW_SIZE 200
36 #define TIMER_ID 1
37
38 CLOCK_GLOBALS Globals;
39
40 static VOID CLOCK_UpdateMenuCheckmarks(VOID)
41 {
42     HMENU hPropertiesMenu;
43     hPropertiesMenu = GetSubMenu(Globals.hMainMenu, 0);
44     if (!hPropertiesMenu)
45         return;
46
47     if(Globals.bAnalog) {
48
49         /* analog clock */
50         CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_ANALOG, MF_CHECKED);
51         EnableMenuItem(hPropertiesMenu, IDM_FONT, MF_GRAYED);
52     }
53     else
54     {
55         /* digital clock */
56         CheckMenuRadioItem(hPropertiesMenu, IDM_ANALOG, IDM_DIGITAL, IDM_DIGITAL, MF_CHECKED);
57         EnableMenuItem(hPropertiesMenu, IDM_FONT, 0);
58     }
59
60     CheckMenuItem(hPropertiesMenu, IDM_NOTITLE, (Globals.bWithoutTitle ? MF_CHECKED : MF_UNCHECKED));
61
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));
65 }
66
67 static VOID CLOCK_UpdateWindowCaption(VOID)
68 {
69     WCHAR szCaption[MAX_STRING_LEN];
70     int chars = 0;
71
72     /* Set frame caption */
73     if (Globals.bDate) {
74         chars = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL,
75                                szCaption, sizeof(szCaption)/sizeof(WCHAR));
76         if (chars) {
77             --chars;
78             szCaption[chars++] = ' ';
79             szCaption[chars++] = '-';
80             szCaption[chars++] = ' ';
81             szCaption[chars] = '\0';
82         }
83     }
84     LoadStringW(0, IDS_CLOCK, szCaption + chars, MAX_STRING_LEN - chars);
85     SetWindowTextW(Globals.hMainWnd, szCaption);
86 }
87
88 /***********************************************************************
89  *
90  *           CLOCK_ResetTimer
91  */
92 static BOOL CLOCK_ResetTimer(void)
93 {
94     UINT period; /* milliseconds */
95
96     KillTimer(Globals.hMainWnd, TIMER_ID);
97
98     if (Globals.bSeconds)
99         if (Globals.bAnalog)
100             period = 50;
101         else
102             period = 500;
103     else
104         period = 1000;
105
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);
111         return FALSE;
112     }
113     return TRUE;
114 }
115
116 /***********************************************************************
117  *
118  *           CLOCK_ResetFont
119  */
120 static VOID CLOCK_ResetFont(VOID)
121 {
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;
128     }
129         
130     ReleaseDC(Globals.hMainWnd, dc);
131 }
132
133
134 /***********************************************************************
135  *
136  *           CLOCK_ChooseFont
137  */
138 static VOID CLOCK_ChooseFont(VOID)
139 {
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;
148     if (ChooseFontW(&cf)) {
149         Globals.logfont = lf;
150         CLOCK_ResetFont();
151     }
152 }
153
154 /***********************************************************************
155  *
156  *           CLOCK_ToggleTitle
157  */
158 static VOID CLOCK_ToggleTitle(VOID)
159 {
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);
165     }
166     else {
167         style = (style & ~(WS_POPUP|WS_THICKFRAME)) | WS_OVERLAPPEDWINDOW;
168         SetMenu(Globals.hMainWnd, Globals.hMainMenu);
169         SetWindowRgn(Globals.hMainWnd, 0, TRUE);
170     }
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);
174     
175     CLOCK_UpdateMenuCheckmarks();
176     CLOCK_UpdateWindowCaption();
177 }
178
179 /***********************************************************************
180  *
181  *           CLOCK_ToggleOnTop
182  */
183 static VOID CLOCK_ToggleOnTop(VOID)
184 {
185     if ((Globals.bAlwaysOnTop = !Globals.bAlwaysOnTop)) {
186         SetWindowPos(Globals.hMainWnd, HWND_TOPMOST, 0,0,0,0,
187                      SWP_NOMOVE|SWP_NOSIZE);
188     }
189     else {
190         SetWindowPos(Globals.hMainWnd, HWND_NOTOPMOST, 0,0,0,0,
191                      SWP_NOMOVE|SWP_NOSIZE);
192     }
193     CLOCK_UpdateMenuCheckmarks();
194 }
195 /***********************************************************************
196  *
197  *           CLOCK_MenuCommand
198  *
199  *  All handling of main menu events
200  */
201
202 static int CLOCK_MenuCommand (WPARAM wParam)
203 {
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;
214         }
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;
223         }
224             /* change font */
225         case IDM_FONT: {
226             CLOCK_ChooseFont();
227             break;
228         }
229             /* hide title bar */
230         case IDM_NOTITLE: {
231             CLOCK_ToggleTitle();
232             break;
233         }
234             /* always on top */
235         case IDM_ONTOP: {
236             CLOCK_ToggleOnTop();
237             break;
238         }
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;
248         }
249             /* show or hide date */
250         case IDM_DATE: {
251             Globals.bDate = !Globals.bDate;
252             CLOCK_UpdateMenuCheckmarks();
253             CLOCK_UpdateWindowCaption();
254             break;
255         }
256             /* show "about" box */
257         case IDM_ABOUT: {
258             LoadStringW(Globals.hInstance, IDS_CLOCK, szApp, sizeof(szApp)/sizeof(WCHAR));
259             lstrcpyW(szAppRelease,szApp);
260             ShellAboutW(Globals.hMainWnd, szApp, szAppRelease, 0);
261             break;
262         }
263     }
264     return 0;
265 }
266
267 /***********************************************************************
268  *
269  *           CLOCK_Paint
270  */
271 static VOID CLOCK_Paint(HWND hWnd)
272 {
273     PAINTSTRUCT ps;
274     HDC dcMem, dc;
275     HBITMAP bmMem, bmOld;
276
277     dc = BeginPaint(hWnd, &ps);
278
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);
283
284     bmOld = SelectObject(dcMem, bmMem);
285
286     SetViewportOrgEx(dcMem, -ps.rcPaint.left, -ps.rcPaint.top, NULL);
287     /* Erase the background */
288     FillRect(dcMem, &ps.rcPaint, GetSysColorBrush(COLOR_3DFACE));
289
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);
294
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);
302
303     SelectObject(dcMem, bmOld);
304     DeleteObject(bmMem);
305     DeleteDC(dcMem);
306     
307     EndPaint(hWnd, &ps);
308 }
309
310 /***********************************************************************
311  *
312  *           CLOCK_WndProc
313  */
314
315 static LRESULT WINAPI CLOCK_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
316 {
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;
324         }
325
326         case WM_NCLBUTTONDBLCLK:
327         case WM_LBUTTONDBLCLK: {
328             CLOCK_ToggleTitle();
329             break;
330         }
331
332         case WM_PAINT: {
333             CLOCK_Paint(hWnd);
334             break;
335
336         }
337
338         case WM_SIZE: {
339             Globals.MaxX = LOWORD(lParam);
340             Globals.MaxY = HIWORD(lParam);
341             if (Globals.bAnalog && Globals.bWithoutTitle)
342             {
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 );
353             }
354             CLOCK_ResetFont();
355             break;
356         }
357
358         case WM_COMMAND: {
359             CLOCK_MenuCommand(wParam);
360             break;
361         }
362             
363         case WM_TIMER: {
364             /* Could just invalidate what has changed,
365              * but it doesn't really seem worth the effort
366              */
367             InvalidateRect(Globals.hMainWnd, NULL, FALSE);
368             break;
369         }
370
371         case WM_DESTROY: {
372             PostQuitMessage (0);
373             break;
374         }
375
376         default:
377             return DefWindowProcW(hWnd, msg, wParam, lParam);
378     }
379     return 0;
380 }
381
382
383 /***********************************************************************
384  *
385  *           WinMain
386  */
387
388 int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
389 {
390     MSG      msg;
391     WNDCLASSW class;
392
393     static const WCHAR szClassName[] = {'C','L','C','l','a','s','s',0};
394     static const WCHAR szWinName[]   = {'C','l','o','c','k',0};
395
396     /* Setup Globals */
397     memset(&Globals.hFont, 0, sizeof (Globals.hFont));
398     Globals.bAnalog         = TRUE;
399     Globals.bSeconds        = TRUE;
400     
401     if (!prev){
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;
412     }
413     
414     if (!RegisterClassW(&class)) return FALSE;
415     
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,
420                                      0, hInstance, 0);
421
422     if (!CLOCK_ResetTimer())
423         return FALSE;
424
425     Globals.hMainMenu = LoadMenuW(0, MAKEINTRESOURCEW(MAIN_MENU));
426     SetMenu(Globals.hMainWnd, Globals.hMainMenu);
427     CLOCK_UpdateMenuCheckmarks();
428     CLOCK_UpdateWindowCaption();
429     
430     ShowWindow (Globals.hMainWnd, show);
431     UpdateWindow (Globals.hMainWnd);
432     
433     while (GetMessageW(&msg, 0, 0, 0)) {
434         TranslateMessage(&msg);
435         DispatchMessageW(&msg);
436     }
437
438     KillTimer(Globals.hMainWnd, TIMER_ID);
439     DeleteObject(Globals.hFont);
440
441     return 0;
442 }