[C] 纯文本查看 复制代码
1| /* Fliqlo-style flip clock screensaver — pure C Win32 GDI
2| * Double-click / no args: settings. /s : screensaver. /c : settings.
3| */
4| #ifndef UNICODE
5| #define UNICODE
6| #endif
7| #ifndef _UNICODE
8| #define _UNICODE
9| #endif
10| #define WIN32_LEAN_AND_MEAN
11| #include <windows.h>
12| #include <windowsx.h>
13| #include <commctrl.h>
14| #include <shellapi.h>
15| #include <stdio.h>
16| #include <stdlib.h>
17| #include <string.h>
18| #include <wchar.h>
19| #include <math.h>
20| #include <time.h>
21| #include "lunar.h"
22|
23| #ifndef CLEARTYPE_NATURAL_QUALITY
24| #define CLEARTYPE_NATURAL_QUALITY 5
25| #endif
26|
27| #ifndef max
28| #define max(a,b) (((a)>(b))?(a):(b))
29| #define min(a,b) (((a)<(b))?(a):(b))
30| #endif
31|
32| #pragma comment(lib, "gdi32")
33| #pragma comment(lib, "user32")
34| #pragma comment(lib, "comctl32")
35| #pragma comment(lib, "shell32")
36| #pragma comment(lib, "advapi32")
37|
38| #define FLIP_MS 420
39| #define SETTLE_MS 1200
40| #define MOUSE_THRESHOLD 8
41| #define MAX_FONTS 512
42| #define ID_FONT 1001
43| #define ID_DATE 1002
44| #define ID_LUNAR 1003
45| #define ID_SEC 1004
46| #define ID_H24 1005
47| #define ID_H12 1006
48| #define ID_START 1007
49| #define ID_SAVE 1008
50| #define ID_CLOSE 1009
51| #define ID_PREVIEW 1010
52| #define ID_TIME_SIZE 1011
53| #define ID_DATE_SIZE 1012
54| #define ID_TIME_VAL 1013
55| #define ID_DATE_VAL 1014
56| #define ID_AMP_SIZE 1015
57| #define ID_AMP_VAL 1016
58| #define ID_DELETE 1017
59| #define ID_INSTALL 1018
60|
61| typedef struct {
62| wchar_t font_family[128];
63| int show_date;
64| int show_lunar;
65| int show_seconds;
66| int hour_format; /* 12 or 24 */
67| int time_scale; /* 50..200 percent, default 100 */
68| int date_scale; /* 50..300 percent, default 100 */
69| int ampm_scale; /* 50..300 percent, size of 上午/下午 */
70| } AppConfig;
71|
72| static AppConfig g_cfg;
73| static wchar_t g_exe_dir[MAX_PATH];
74| static wchar_t g_config_path[MAX_PATH];
75| static wchar_t g_font_list[MAX_FONTS][128];
76| static int g_font_count = 0;
77| static int g_want_run = 0;
78|
79| static HWND g_hwndSettings = NULL;
80| static HWND g_hwndClock = NULL;
81| static int g_running = 0;
82| static POINT g_lastMouse;
83| static DWORD g_startTick = 0;
84|
85| typedef struct {
86| RECT rc;
87| wchar_t current;
88| wchar_t next;
89| int flipping;
90| DWORD t0;
91| HBITMAP bmp_cur;
92| HBITMAP bmp_next;
93| wchar_t cache_cur;
94| wchar_t cache_next;
95| int cache_w;
96| int cache_h;
97| } DigitCard;
98|
99| static DigitCard g_cards[6];
100| static int g_nCards = 0;
101| static POINT g_colons[2];
102| static int g_nColons = 0;
103| static int g_cardH = 0;
104| static HBITMAP g_backBmp = NULL;
105| static HDC g_backDC = NULL;
106| static int g_sw = 0, g_sh = 0;
107| static HFONT g_digitFont = NULL;
108| static HFONT g_dateFont = NULL;
109| static HFONT g_ampFont = NULL;
110| static int g_digitFontSize = -1;
111| static int g_dateFontSize = -1;
112| static wchar_t g_cachedFace[128] = {0};
113|
114| /* Colors */
115| static COLORREF COL_BG = RGB(8, 8, 10);
116| static COLORREF COL_CARD = RGB(28, 28, 32);
117| static COLORREF COL_EDGE = RGB(18, 18, 22);
118| static COLORREF COL_DIGIT = RGB(236, 232, 220);
119| static COLORREF COL_DATE = RGB(140, 140, 148);
120| static COLORREF COL_COLON = RGB(210, 205, 190);
121| static COLORREF COL_AMP = RGB(180, 176, 164);
122|
123| static void get_exe_dir(void) {
124| wchar_t path[MAX_PATH];
125| GetModuleFileNameW(NULL, path, MAX_PATH);
126| wchar_t *slash = wcsrchr(path, L'\\');
127| if (slash) *slash = 0;
128| else wcscpy(path, L".");
129| wcsncpy(g_exe_dir, path, MAX_PATH - 1);
130| swprintf(g_config_path, MAX_PATH, L"%s\\config.ini", g_exe_dir);
131| }
132|
133| static const wchar_t *REG_SUBKEY = L"Software\\FliqloClockC";
134|
135| static int reg_read_dword(HKEY hk, const wchar_t *name, int defv) {
136| DWORD val = 0, typ = 0, cb = sizeof(val);
137| if (RegQueryValueExW(hk, name, NULL, &typ, (LPBYTE)&val, &cb) == ERROR_SUCCESS && typ == REG_DWORD)
138| return (int)val;
139| return defv;
140| }
141|
142| static void load_config(void) {
143| HKEY hk = NULL;
144| /* Defaults first — never use config.ini */
145| wcscpy(g_cfg.font_family, L"Microsoft YaHei");
146| g_cfg.show_date = 1;
147| g_cfg.show_lunar = 0;
148| g_cfg.show_seconds = 0;
149| g_cfg.hour_format = 24;
150| g_cfg.time_scale = 100;
151| g_cfg.date_scale = 100;
152| g_cfg.ampm_scale = 100;
153|
154| if (RegOpenKeyExW(HKEY_CURRENT_USER, REG_SUBKEY, 0, KEY_READ, &hk) != ERROR_SUCCESS)
155| return;
156|
157| {
158| wchar_t buf[128];
159| DWORD typ = 0, cb = sizeof(buf);
160| if (RegQueryValueExW(hk, L"font_family", NULL, &typ, (LPBYTE)buf, &cb) == ERROR_SUCCESS
161| && typ == REG_SZ && buf[0]) {
162| wcsncpy(g_cfg.font_family, buf, 127);
163| g_cfg.font_family[127] = 0;
164| }
165| }
166| g_cfg.show_date = reg_read_dword(hk, L"show_date", g_cfg.show_date) ? 1 : 0;
167| g_cfg.show_lunar = reg_read_dword(hk, L"show_lunar", g_cfg.show_lunar) ? 1 : 0;
168| g_cfg.show_seconds = reg_read_dword(hk, L"show_seconds", g_cfg.show_seconds) ? 1 : 0;
169| g_cfg.hour_format = reg_read_dword(hk, L"hour_format", g_cfg.hour_format);
170| if (g_cfg.hour_format != 12) g_cfg.hour_format = 24;
171| g_cfg.time_scale = reg_read_dword(hk, L"time_scale", g_cfg.time_scale);
172| g_cfg.date_scale = reg_read_dword(hk, L"date_scale", g_cfg.date_scale);
173| g_cfg.ampm_scale = reg_read_dword(hk, L"ampm_scale", g_cfg.ampm_scale);
174| if (g_cfg.time_scale < 50) g_cfg.time_scale = 50;
175| if (g_cfg.time_scale > 200) g_cfg.time_scale = 200;
176| if (g_cfg.date_scale < 50) g_cfg.date_scale = 50;
177| if (g_cfg.date_scale > 300) g_cfg.date_scale = 300;
178| if (g_cfg.ampm_scale < 50) g_cfg.ampm_scale = 50;
179| if (g_cfg.ampm_scale > 300) g_cfg.ampm_scale = 300;
180| RegCloseKey(hk);
181| }
182|
183| static void reg_write_dword(HKEY hk, const wchar_t *name, int v) {
184| DWORD val = (DWORD)v;
185| RegSetValueExW(hk, name, 0, REG_DWORD, (const BYTE *)&val, sizeof(val));
186| }
187|
188| static void save_config(void) {
189| /* Persist to HKCU registry only — never create config.ini beside exe */
190| HKEY hk = NULL;
191| DWORD disp = 0;
192| if (RegCreateKeyExW(HKEY_CURRENT_USER, REG_SUBKEY, 0, NULL, 0,
193| KEY_WRITE, NULL, &hk, &disp) != ERROR_SUCCESS)
194| return;
195| RegSetValueExW(hk, L"font_family", 0, REG_SZ,
196| (const BYTE *)g_cfg.font_family,
197| (DWORD)((wcslen(g_cfg.font_family) + 1) * sizeof(wchar_t)));
198| reg_write_dword(hk, L"show_date", g_cfg.show_date);
199| reg_write_dword(hk, L"show_lunar", g_cfg.show_lunar);
200| reg_write_dword(hk, L"show_seconds", g_cfg.show_seconds);
201| reg_write_dword(hk, L"hour_format", g_cfg.hour_format);
202| reg_write_dword(hk, L"time_scale", g_cfg.time_scale);
203| reg_write_dword(hk, L"date_scale", g_cfg.date_scale);
204| reg_write_dword(hk, L"ampm_scale", g_cfg.ampm_scale);
205| RegCloseKey(hk);
206| (void)g_config_path;
207| }
208|