1: /*
2: ============================================================================
3: xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
4: Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
5: Copyright © 2001-2004 The Blackbox for Windows Development Team
6: http://xoblite.net/ + https://github.com/xoblite/
7: ============================================================================
8:
9: Blackbox for Windows is free software, released under the
10: GNU General Public License (GPL version 2 or later), with an extension
11: that allows linking of proprietary modules under a controlled interface.
12: What this means is that plugins etc. are allowed to be released
13: under any license the author wishes. Please note, however, that the
14: original Blackbox gradient math code used in Blackbox for Windows
15: is available under the BSD license.
16:
17: http://www.fsf.org/licenses/gpl.html
18: http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
19: http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
20:
21: This program is distributed in the hope that it will be useful,
22: but WITHOUT ANY WARRANTY; without even the implied warranty of
23: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24: GNU General Public License for more details.
25:
26: For additional license information, please read the included license.html.
27:
28: ============================================================================
29: */
30:
31: #include "Themes.h"
32: #include <io.h>
33:
34: extern Settings* pSettings;
35: extern Desktop* pDesktop;
36:
37: typedef struct fontListItem
38: {
39: char fontFile[MAX_PATH];
40: } fontListItem;
41:
42: typedef vector<fontListItem*> fontListVector;
43: fontListVector fontList;
44:
45: //===========================================================================
46:
47: bool SetTheme(LPSTR themePath, bool startingUp)
48: {
49: if (startingUp) ZeroMemory(&fontList, sizeof(fontList));
50:
51: if (themePath != 0)
52: {
53: char path[MAX_LINE_LENGTH], theme[MAX_LINE_LENGTH];
54: strcpy_s(theme, sizeofArray(theme), themePath);
55: if (strchr(theme, '\"')) StrRemoveEncap(theme);
56: if (strchr(theme, '$')) ReplaceShellFolders(theme);
57: if (strchr(theme, '%')) ReplaceEnvVars(theme);
58: if (theme[strnlen_s(theme, sizeofArray(theme))-1] == '\\') theme[strnlen_s(theme, sizeofArray(theme))-1] = 0;
59:
60: //====================
61:
62: // Is the requested theme the same as the current theme? If so, just reload it... (i.e. restart operation)
63: if (!startingUp && !_stricmp(pSettings->SF_currentThemePath, theme))
64: {
65: char temp[MAX_LINE_LENGTH];
66: if (!_stricmp(pSettings->selectedTheme, "[Default]")) strcpy_s(temp, sizeofArray(temp), "Reloading the default theme...");
67: else sprintf_s(temp, sizeofArray(temp), "Reloading the \"%s\" theme...", pSettings->selectedTheme);
68: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)temp);
69:
70: restartBlackboxStop();
71: UnregisterThemeFonts();
72: RegisterThemeFonts();
73: restartBlackboxStart();
74:
75: PlaySoundFX(SFX_THEME_CHANGE);
76:
77: return true;
78: }
79:
80: //====================
81:
82: // Otherwise, first make sure the requested theme is valid...
83: // (i.e. being either the [Default] theme, or another theme having at least a configuration xoblite.rc/blackbox.rc file)
84: bool validTheme = !_stricmp(pSettings->SF_blackboxPath, theme);
85: if (!validTheme)
86: {
87: strcpy_s(path, sizeofArray(path), theme);
88: strcat_s(path, sizeofArray(path), "\\xoblite.rc");
89: validTheme = FileExists(path);
90: if (!validTheme)
91: {
92: strcpy_s(path, sizeofArray(path), theme);
93: strcat_s(path, sizeofArray(path), "\\blackbox.rc");
94: validTheme = FileExists(path);
95: }
96: }
97:
98: if (validTheme)
99: {
100: // Save settings, unload plugins etc...
101: if (!startingUp) restartBlackboxStop();
102:
103: // Unload font resources for the old theme...
104: if (!startingUp) UnregisterThemeFonts();
105:
106: // Set the new theme path...
107: strcpy_s(pSettings->SF_currentThemePath, sizeofArray(pSettings->SF_currentThemePath), theme);
108: pSettings->usingDefaultTheme = !_stricmp(pSettings->SF_blackboxPath, pSettings->SF_currentThemePath);
109:
110: //====================
111:
112: // Are we using the [Default] theme?
113: if (pSettings->usingDefaultTheme)
114: {
115: // Reset the main configuration file paths to initiate
116: // a new ConfigFileExists check for each of them...
117: strcpy_s(pSettings->bbrcFile, sizeofArray(pSettings->bbrcFile), "");
118: bbrcPath();
119:
120: strcpy_s(pSettings->xobrcFile, sizeofArray(pSettings->xobrcFile), "");
121: extensionsrcPath();
122: strcpy_s(pSettings->xobrcDefaultFile, sizeofArray(pSettings->xobrcDefaultFile), pSettings->xobrcFile);
123:
124: // strcpy_s(pSettings->pluginsFile, sizeofArray(pSettings->pluginsFile), "");
125: // plugrcPath();
126:
127: if (!startingUp)
128: {
129: pSettings->writeProtection = false;
130: strcpy_s(pSettings->selectedTheme, sizeofArray(pSettings->selectedTheme), "[Default]");
131: WriteString(pSettings->xobrcDefaultFile, "xoblite.selected.theme:", pSettings->selectedTheme);
132:
133: // Show theme change message in the console...
134: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)"Switching to the default theme...");
135: }
136: }
137:
138: //====================
139:
140: else // Nope, we are using any other theme than the [Default] theme...
141: {
142: // Set the new theme's configuration file paths...
143: strcpy_s(path, sizeofArray(path), pSettings->SF_currentThemePath);
144: strcat_s(path, sizeofArray(path), "\\xoblite.rc");
145: if (FileExists(path))
146: {
147: bbrcPath(path);
148: extensionsrcPath(path);
149: }
150: else
151: {
152: strcpy_s(path, sizeofArray(path), pSettings->SF_currentThemePath);
153: strcat_s(path, sizeofArray(path), "\\blackbox.rc");
154: if (FileExists(path)) bbrcPath(path);
155: strcpy_s(path, sizeofArray(path), pSettings->SF_currentThemePath);
156: strcat_s(path, sizeofArray(path), "\\extensions.rc");
157: if (FileExists(path)) extensionsrcPath(path);
158: }
159: /*
160: // strcpy_s(path, sizeofArray(path), pSettings->SF_currentThemePath);
161: // strcat_s(path, sizeofArray(path), "\\plugins.rc");
162: // strcpy_s(path, sizeofArray(path), pSettings->pluginsFile);
163: // if (FileExists(path)) plugrcPath(path);
164: // else
165: strcpy_s(pSettings->pluginsFile, sizeofArray(pSettings->pluginsFile), ReadString(pSettings->xobrcDefaultFile, "xoblite.pluginsFile:", "$Blackbox$\\plugins.rc"));
166: if (strchr(pSettings->pluginsFile, '\"')) StrRemoveEncap(pSettings->pluginsFile);
167: if (strchr(pSettings->pluginsFile, '$')) ReplaceShellFolders(pSettings->pluginsFile);
168: if (strchr(pSettings->pluginsFile, '%')) ReplaceEnvVars(pSettings->pluginsFile);
169:
170: if (!FileExists(pSettings->pluginsFile))
171: {
172: // Reset plugin.rc file path to initiate a new ConfigFileExists check...
173: // (this allows for xoblite.rc (or bb+ext.rc) only themes using a global plugins.rc)
174: // strcpy_s(pSettings->pluginsFile, sizeofArray(pSettings->pluginsFile), "");
175: GetBlackboxPath(path, sizeof(path));
176: strcat_s(path, sizeofArray(path), "\\plugins.rc");
177: plugrcPath();
178: }
179: */
180: if (!startingUp)
181: {
182: pSettings->writeProtection = false;
183: strcpy_s(pSettings->selectedTheme, sizeofArray(pSettings->selectedTheme), &pSettings->SF_currentThemePath[strnlen_s(pSettings->themesFolder, sizeofArray(pSettings->themesFolder))+1]);
184: WriteString(pSettings->xobrcDefaultFile, "xoblite.selected.theme:", pSettings->selectedTheme);
185:
186: // Show theme change message in the console...
187: char temp[MAX_LINE_LENGTH];
188: sprintf_s(temp, sizeofArray(temp), "Switching to the \"%s\" theme...", pSettings->selectedTheme);
189: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)temp);
190: }
191: }
192:
193: //====================
194:
195: if (!startingUp)
196: {
197: // Load font resources for the new theme...
198: RegisterThemeFonts();
199:
200: // Finally, we load the new theme settings...
201: restartBlackboxStart();
202: // ...and point out the theme change audibly as well... ;)
203: PlaySoundFX(SFX_THEME_CHANGE);
204:
205: pSettings->Statistics.changedTheme++; // Update statistics...
206: }
207: }
208:
209: //====================
210:
211: else if (!startingUp)
212: {
213: // The specified theme path wasn't valid!
214: char msg[MAX_LINE_LENGTH];
215: sprintf_s(msg, sizeofArray(msg), "%s \n\ndoes not seem to be a valid theme path. \nPlease check your related configuration file. ", themePath);
216: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
217: return false;
218: }
219: }
220:
221: return false;
222: }
223:
224: //===========================================================================
225: // Function: RegisterThemeFonts / UnregisterThemeFonts
226: // Purpose: Dynamically adds / removes theme specific font resources
227: //===========================================================================
228:
229: void RegisterThemeFonts()
230: {
231: if (fontList.size() > 0) UnregisterThemeFonts(); // Safeguard
232: if (pSettings->disableThemeFonts) return;
233:
234: char fontsFolder[MAX_PATH];
235: strcpy_s(fontsFolder, sizeofArray(fontsFolder), pSettings->SF_currentThemePath);
236: strcat_s(fontsFolder, sizeofArray(fontsFolder), "\\fonts");
237: if (!FolderExists(fontsFolder))
238: {
239: strcpy_s(fontsFolder, sizeofArray(fontsFolder), pSettings->SF_blackboxPath);
240: strcat_s(fontsFolder, sizeofArray(fontsFolder), "\\fonts");
241: }
242:
243: if (FolderExists(fontsFolder))
244: {
245: char searchPattern[MAX_PATH];
246: strcpy_s(searchPattern, sizeofArray(searchPattern), fontsFolder);
247: strcat_s(searchPattern, sizeofArray(searchPattern), "\\*");
248:
249: _finddata_t found;
250: long handle = _findfirst(searchPattern, &found);
251: if (handle != -1)
252: {
253: char fontFile[MAX_PATH];
254:
255: do
256: {
257: // Skip hidden files and any subfolders... (nb. we only register fonts in the main /fonts folder for a theme!)
258: if (strcmp(found.name, ".") == 0 || strcmp(found.name, "..") == 0 || (found.attrib & _A_HIDDEN)) continue;
259: if (found.attrib & _A_SUBDIR) continue;
260:
261: // Have we found a valid font file?
262: if (IsInString(found.name, ".ttf") || IsInString(found.name, ".otf") || IsInString(found.name, ".fon"))
263: {
264: // Add the font resource, marked as private to our process, to the system...
265: sprintf_s(fontFile, sizeofArray(fontFile), "%s\\%s", fontsFolder, found.name);
266: if (AddFontResourceEx(fontFile, FR_PRIVATE, 0) > 0)
267: {
268: fontListItem* addedFont = new fontListItem;
269: strcpy_s(addedFont->fontFile, sizeofArray(addedFont->fontFile), fontFile);
270: fontList.push_back(addedFont);
271: }
272: }
273: }
274: while (_findnext(handle, &found) == 0);
275: }
276:
277: _findclose(handle);
278:
279: if (fontList.size() > 0)
280: {
281: PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
282:
283: char msg[255];
284: if (fontList.size() > 1) sprintf_s(msg, sizeofArray(msg), "Adding theme fonts -> %d fonts registered.", fontList.size());
285: else sprintf_s(msg, sizeofArray(msg), "Adding theme fonts -> %d font registered.", fontList.size());
286: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
287: }
288: }
289: }
290:
291: //====================
292:
293: void UnregisterThemeFonts()
294: {
295: if (fontList.empty()) return;
296:
297: int fontsUnregistered = fontList.size();
298:
299: for (int i=0; i<(int)fontList.size(); i++)
300: {
301: RemoveFontResourceEx(fontList[i]->fontFile, FR_PRIVATE, 0);
302: delete fontList[i];
303: }
304: fontList.clear();
305: // ZeroMemory(&fontList, sizeof(fontList));
306:
307: PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
308: /*
309: if (pSettings->debugLogging)
310: {
311: char msg[255];
312: if (fontsUnregistered > 1) sprintf_s(msg, sizeofArray(msg), "Removing theme fonts -> %d fonts unregistered.", fontsUnregistered);
313: else sprintf_s(msg, sizeofArray(msg), "Removing theme fonts -> %d font unregistered.", fontsUnregistered);
314: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
315: }
316: */
317: }
318:
319: //===========================================================================
320: