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: #pragma warning(disable: 4996) // "'GetVersionExA' was declared deprecated"
32:
33: #include "BBApi.h"
34: #include "..\Graphics\BImage.h"
35: //#include "..\Desktop\Desktop.h"
36: #include "..\Plugins\PluginManager.h"
37: #include "..\Toolbar\Taskbar.h"
38: #include "..\Workspaces\Workspaces.h"
39: //#include "..\Menu\Menu.h"
40: #include "..\Menu\MenuCommon.h"
41: //#include "..\Menu\MenuItem.h"
42: //#include "..\Menu\FolderItem.h"
43: //#include "..\Settings\Settings.h"
44: #include "..\Desktop\Wallpaper.h"
45:
46: //#include <stdlib.h>
47: //#include <stdio.h>
48: #include <time.h>
49: #include <shellapi.h>
50: //#include <winver.h>
51: #include <shlwapi.h>
52: #include <versionhelpers.h>
53:
54: #include <gdiplus.h>
55: using namespace Gdiplus;
56:
57: //===========================================================================
58:
59: // Transparency defines - just in case... <g>
60: #ifndef WS_EX_LAYERED
61: #define WS_EX_LAYERED 0x00080000
62: #endif
63: #ifndef LWA_COLORKEY
64: #define LWA_COLORKEY 0x00000001
65: #endif
66: #ifndef LWA_ALPHA
67: #define LWA_ALPHA 0x00000002
68: #endif
69:
70: //===========================================================================
71:
72: extern BImage *pBImage;
73: extern Menu *pMenu;
74: extern MenuCommon *pMenuCommon;
75: extern PluginManager *pPluginManager;
76: extern Taskbar *pTaskbar;
77: extern Workspaces *pWorkspaces;
78: extern Settings *pSettings;
79: extern Desktop *pDesktop;
80: extern Wallpaper* pWallpaper;
81:
82: static char tempBuf[MAX_LINE_LENGTH];
83: static char lineFromFile[MAX_LINE_LENGTH+1];
84:
85: typedef vector<HWND> StickyWindowsVector;
86: StickyWindowsVector stickyWindows;
87:
88: //LPSTR ReadValue(LPCSTR fp, LPCSTR keyword, LPLONG ptr = NULL);
89: COLORREF ParseLiteralColor(LPCSTR color);
90:
91: HWND hBlackbox = NULL;
92:
93: bool hideNamedMenu = false;
94:
95: typedef BOOL (WINAPI *LPFN_WOW64_DISABLE_REDIRECTION)(PVOID);
96: typedef BOOL (WINAPI *LPFN_WOW64_REVERT_REDIRECTION)(PVOID);
97:
98: //===========================================================================
99: // Function: GetBBVersion
100: // Purpose: Returns the current version of the core shell .exe
101: // In: None
102: // Out: LPCSTR = Formatted version string
103: //===========================================================================
104:
105: LPCSTR GetBBVersion()
106: {
107: char buffer[MAX_LINE_LENGTH];
108: ULONG *size = 0;
109: DWORD number = GetFileVersionInfoSize("Blackbox.exe", size);
110: GetFileVersionInfo("Blackbox.exe", NULL, number, (LPVOID)buffer);
111:
112: void *value;
113: UINT bytes;
114: // Make sure the correct version encoding is used (currently "000004b0" = language neutral)
115: VerQueryValue(buffer, TEXT("\\StringFileInfo\\000004b0\\ProductVersion"), &value, &bytes);
116: strcpy_s(tempBuf, sizeofArray(tempBuf), (LPCSTR)value);
117:
118: return tempBuf;
119: }
120:
121: //===========================================================================
122: // Function: GetBBWnd
123: // Purpose: Returns the handle to the main Blackbox window
124: // In: None
125: // Out: HWND = Handle to the Blackbox window
126: //===========================================================================
127:
128: HWND GetBBWnd()
129: {
130: if (!hBlackbox) hBlackbox = FindWindow("xoblite", NULL);
131: return hBlackbox;
132: }
133:
134: //===========================================================================
135: // Function: GetOSInfo
136: // Purpose: Retrieves info about the current OS
137: // In: None
138: // Out: LPCSTR = Returns a readable string containing the OS name
139: //===========================================================================
140:
141: LPCSTR GetOSInfo(void)
142: {
143: char buffer[MAX_LINE_LENGTH];
144:
145: OSVERSIONINFO osv;
146: ZeroMemory(&osv, sizeof(osv));
147: osv.dwOSVersionInfoSize = sizeof(osv);
148: GetVersionEx(&osv);
149:
150: if (IsWindows10OrGreater())
151: {
152: if (osv.dwBuildNumber >= 22000) strcpy_s(buffer, sizeofArray(buffer), "Windows 11"); // PLACEHOLDER - No IsWindows11OrGreater() function available in the Windows API yet (?)
153: else strcpy_s(buffer, sizeofArray(buffer), "Windows 10");
154: }
155: else if (IsWindows8Point1OrGreater()) strcpy_s(buffer, sizeofArray(buffer), "Windows 8.1");
156: else if (IsWindows8OrGreater()) strcpy_s(buffer, sizeofArray(buffer), "Windows 8");
157: else if (IsWindows7OrGreater()) strcpy_s(buffer, sizeofArray(buffer), "Windows 7");
158: else if (IsWindowsVistaOrGreater()) strcpy_s(buffer, sizeofArray(buffer), "Windows Vista");
159: else
160: {
161: // As per Microsoft: "In Windows 8.1 and Windows 10, the GetVersion and GetVersionEx functions have been deprecated.
162: // In Windows 10, the VerifyVersionInfo function has also been deprecated. While you can still call the
163: // deprecated functions, if your application does not specifically target Windows 8.1 or Windows 10,
164: // the functions will return the Windows 8 version (6.2)."
165: // ### -> Added a basic application manifest with compatibility settings, see Resources/Compatbility.manifest ###
166:
167: if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) // Windows 9x/ME
168: {
169: if (osv.dwMinorVersion >= 90) strcpy_s(buffer, sizeofArray(buffer), "Windows ME");
170: else if (osv.dwMinorVersion >= 10) strcpy_s(buffer, sizeofArray(buffer), "Windows 98");
171: else strcpy_s(buffer, sizeofArray(buffer), "Windows 95");
172: }
173: else // Windows NT/2000/XP/Vista/7/8/8.1/10/11... (nb. not including server variants here as alternative shells are really only for clients anyway)
174: {
175: sprintf_s(buffer, sizeofArray(buffer), "Windows NT %d.%d", osv.dwMajorVersion, osv.dwMinorVersion); // Fallback in case of unknown Windows version...
176:
177: if (osv.dwMajorVersion == 10)
178: {
179: if (osv.dwMinorVersion == 0)
180: {
181: if (osv.dwBuildNumber >= 22000) strcpy_s(buffer, sizeofArray(buffer), "Windows 11");
182: else strcpy_s(buffer, sizeofArray(buffer), "Windows 10");
183: }
184: }
185: else if (osv.dwMajorVersion == 6)
186: {
187: if (osv.dwMinorVersion == 3) strcpy_s(buffer, sizeofArray(buffer), "Windows 8.1");
188: else if (osv.dwMinorVersion == 2) strcpy_s(buffer, sizeofArray(buffer), "Windows 8");
189: else if (osv.dwMinorVersion == 1) strcpy_s(buffer, sizeofArray(buffer), "Windows 7");
190: else if (osv.dwMinorVersion == 0) strcpy_s(buffer, sizeofArray(buffer), "Windows Vista");
191: }
192: else if (osv.dwMajorVersion == 5)
193: {
194: if (osv.dwMinorVersion == 2) strcpy_s(buffer, sizeofArray(buffer), "Windows XP (64-bit)");
195: else if (osv.dwMinorVersion == 1) strcpy_s(buffer, sizeofArray(buffer), "Windows XP (32-bit)");
196: else if (osv.dwMinorVersion == 0) strcpy_s(buffer, sizeofArray(buffer), "Windows 2000");
197: }
198: }
199: }
200:
201: strcpy_s(tempBuf, sizeofArray(tempBuf), buffer);
202:
203: return tempBuf;
204: }
205:
206: //===========================================================================
207: // Function: GetBlackboxPath
208: // Purpose: Copies the path of the Blackbox executable to the specified buffer
209: // In: LPSTR pszPath = Location of the buffer for the path
210: // In: int nMaxLen = Maximum length for the buffer
211: // Out: bool = Returns status of completion
212: //===========================================================================
213:
214: bool WINAPI GetBlackboxPath(LPSTR pszPath, int nMaxLen)
215: {
216: static char szPath[MAX_PATH] = "";
217:
218: if (!szPath[0])
219: {
220: GetModuleFileName(NULL, szPath, MAX_PATH);
221: // int nLen = strnlen_s(szPath, sizeofArray(szPath)) - 1;
222: // while (nLen > 0 && szPath[nLen] != '\\') nLen--;
223: // szPath[nLen+1] = 0;
224: GetParentFolder(szPath);
225: }
226:
227: strncpy(pszPath, szPath, nMaxLen);
228:
229: return true;
230: }
231:
232: //===========================================================================
233: // Function: FileOpen
234: // Purpose: Open a file for parsing
235: // In: LPCSTR = Path of file to open
236: // Out: FILE* = Pointer to the opened file
237: //===========================================================================
238:
239: FILE *FileOpen(LPCSTR szPath)
240: {
241: FILE *file = NULL;
242: if (FileExists(szPath)) file = fopen(szPath, "r");
243:
244: return (file);
245: }
246:
247: //===========================================================================
248: // Function: FileClose
249: // Purpose: Close a previously opened file
250: // In: FILE *fp = The file to close
251: // Out: bool = Returns the status of completion
252: //===========================================================================
253:
254: bool FileClose(FILE *fp)
255: {
256: if (fp)
257: {
258: if (fclose(fp)) return false;
259: else return true;
260: }
261: else return false;
262: }
263:
264: //===========================================================================
265: // Function: Tokenize
266: // Purpose: Retrieve the first string separated by the delim and return a pointer to the rest of the string
267: // In: LPCSTR string = String to be parsed
268: // In: LPSTR buf = String where the tokenized string will be placed
269: // In: LPSTR delims = The delimeter that signifies the separation of the tokens in the string
270: // Out: LPSTR = Returns a pointer to the entire remaining string
271: //===========================================================================
272:
273: LPSTR Tokenize(LPCSTR string, LPSTR buf, LPSTR delims)
274: {
275: static char remaining[MAX_LINE_LENGTH];
276: strcpy_s(remaining, sizeofArray(remaining), string);
277:
278: char character, quoted = 0, *b = buf, *r = remaining;
279:
280: while ((character = *r) != 0)
281: {
282: r++;
283:
284: if (!quoted)
285: {
286: if (strchr(delims, character)) break; // User-specified delimiter
287: else if (character == '\"' || character == '\'') quoted = character;
288: else if (((unsigned char)character <= 32) && (b == buf)) continue;
289: }
290: else if (character == quoted) quoted = 0;
291:
292: *b++ = character;
293: }
294:
295: while ((b > buf) && ((unsigned char)b[-1] <= 32)) b--;
296:
297: *b = '\0';
298:
299: while (((unsigned char)*r <= 32) && (*r)) r++;
300:
301: strcpy_s(remaining, sizeofArray(remaining), r);
302:
303: return remaining;
304: }
305:
306: //===========================================================================
307: // Function: BBTokenize
308: // Purpose: Assigns a specified number of string variables and outputs the remaining to a variable
309: // In: LPCSTR szString = The string to be parsed
310: // In: LPSTR lpszBuffers[] = A pointer to the location for the tokenized strings
311: // In: DWORD dwNumBuffers = The amount of tokens to be parsed
312: // In: LPSTR szExtraParameters = A pointer to the location for the remaining string
313: // Out: int = Number of tokens parsed
314: //===========================================================================
315:
316: int BBTokenize (LPCSTR szString, char *lpszBuffers[], DWORD dwNumBuffers, LPSTR szExtraParameters)
317: {
318: int inputIndex = 0, outputIndex, numberOfTokens = 0;
319: DWORD dwBufferCount = 0;
320: char quoteChar = 0, currentChar, *outputBuffer;
321:
322: //====================
323:
324: while (dwBufferCount < dwNumBuffers)
325: {
326: outputBuffer = lpszBuffers[dwBufferCount];
327: outputIndex = 0;
328:
329: //====================
330:
331: while ((currentChar = szString[inputIndex]) != 0)
332: {
333: inputIndex++;
334:
335: switch (currentChar)
336: {
337: //====================
338:
339: case ' ':
340: case '\t':
341: {
342: if (quoteChar) goto storeThisChar; // We're inside a quoted string, store spaces/tabs just like other characters...
343: if (outputIndex) goto finishedToken; // ...otherwise a space/tab specifies the end of a token
344: continue;
345: }
346:
347: //====================
348:
349: case '"':
350: case '\'':
351: {
352: if (quoteChar == 0) // Quoted string begins here...
353: {
354: // Remember which quote character was used...
355: quoteChar = currentChar;
356: continue;
357: }
358: else if (quoteChar == currentChar) // Quoted string ends here...
359: {
360: // Reset quote character and finish parsing of the current token...
361: quoteChar = 0;
362: goto finishedToken;
363: }
364: else goto storeThisChar;
365: }
366:
367: //====================
368:
369: storeThisChar:
370: default:
371: {
372: // Write current character to output buffer...
373: outputBuffer[outputIndex] = currentChar;
374: outputIndex++;
375: continue;
376: }
377:
378: //====================
379: }
380: }
381:
382: //====================
383:
384: // Finish parsing of the current token...
385: if (outputIndex) finishedToken: numberOfTokens++;
386: outputBuffer[outputIndex]=0;
387: dwBufferCount++;
388: }
389:
390: //====================
391:
392: if (szExtraParameters) strcpy(szExtraParameters, szString + inputIndex);
393:
394: return numberOfTokens;
395: }
396:
397: //===========================================================================
398: // Function: StrRemoveEncap
399: // Purpose: Removes the first and last characters of a string
400: // In: LPSTR string = The string to be altered
401: // Out: LPSTR = A pointer to the altered string
402: // Warning: This will remove the first and last characters from ANY string, so don't use it unless you know that it has the chars there
403: // Warning: My suggestion would be to use strchr() to search the string for the appropriate encaps before you remove them, just to make sure
404: //===========================================================================
405:
406: LPSTR StrRemoveEncap(LPSTR string)
407: {
408: int nLen = strlen(string);
409: nLen--;
410: memmove(string, string+1, nLen-1);
411: *(string+nLen-1) = '\0';
412: return string;
413: }
414: /*
415: LPWSTR StrRemoveEncapUnicode(LPWSTR string)
416: {
417: int nLen = wcslen(string);
418: nLen--;
419: memmove(string, string+1, nLen-1);
420: *(string+nLen-1) = '\0';
421: return string;
422: }
423: */
424: //===========================================================================
425: // Function: ReadValue
426: // Purpose: Opens given file and searches the file for the supplied keyword and returns a pointer to the value
427: // In: LPCSTR fp = String containing the name of the file to be opened
428: // In: LPCSTR keyword = String containing the keyword to be looked for
429: // In: LPLONG ptr = Pointer to the position to start from (defaults to NULL)
430: // Out: LPSTR = Pointer to the value of the keyword
431: //===========================================================================
432:
433: LPSTR ReadValue(LPCSTR fp, LPCSTR keyword, LPLONG ptr)
434: {
435: FILE *f = FileOpen(fp);
436: if (!f) return NULL;
437:
438: //====================
439:
440: // Move to starting position if specified...
441: if (ptr && *ptr != 0) fseek(f, *ptr, SEEK_SET);
442: else fseek(f, 0, SEEK_SET);
443:
444: //====================
445:
446: LONG fpos = 0;
447: char* currentLine;
448:
449: while (FileRead(f, lineFromFile))
450: {
451: lineFromFile[MAX_LINE_LENGTH-1] = '\0'; // Failsafe
452:
453: currentLine = lineFromFile;
454: currentLine += strspn(currentLine, " \t\r\n");
455:
456: // Is the current line a comment line?
457: if (*currentLine == '#' || *currentLine == '!')
458: {
459: fpos = ftell(f);
460: continue;
461: }
462: // If not, look for the keyword a the beginning of the string...
463: else if (!_strnicmp(currentLine, keyword, strlen(keyword)))
464: {
465: // We're only interested in the string after the keyword...
466: currentLine += strlen(keyword);
467: // Remove any space characters, tabs or returns...
468: currentLine += strspn(currentLine, " \t\r\n");
469: // Remove any trailing space characters...
470: int nLen = strlen(currentLine) - 1;
471: while (nLen >0 && currentLine[nLen] == ' ') nLen--;
472: currentLine[nLen+1] = 0;
473:
474: if (ptr) *ptr = fpos;
475: FileClose(f);
476:
477: return (char*)currentLine;
478: }
479:
480: fpos = ftell(f);
481: }
482:
483: //====================
484:
485: FileClose(f);
486:
487: return NULL;
488: }
489:
490: //===========================================================================
491: // Function: ReadBool
492: // Purpose: Read's a string in the given file and outputs the result as a boolean
493: // In: LPCSTR fp = File to be searched
494: // In: LPCSTR szString = Keyword to search for
495: // In: bool szDefault = Default value to return if not found
496: // Out: bool = Returns the value of the found bool
497: //===========================================================================
498:
499: bool ReadBool(LPCSTR fp, LPCSTR szString, bool szDefault)
500: {
501: /*
502: // NULL/empty filepointers are not supported for ReadBool,
503: // but since it is the only Read* function that does not
504: // support them I have added a safeguard here to prevent
505: // a borked plugin from crashing the core... <g>
506: if(!fp || ! _stricmp(fp, "")) return szDefault;
507:
508: LPSTR buffer = ReadValue(fp, szString);
509: if (buffer)
510: {
511: if (! _stricmp(buffer, "true")) return true;
512: else if (! _stricmp(buffer, "false")) return false;
513: else return szDefault;
514: }
515:
516: return szDefault;
517: */
518: return pSettings->GetBool(fp, NULL, szString, szDefault);
519: }
520:
521: //===========================================================================
522: // Function: ReadInt
523: // Purpose: Searches given file for int value
524: // In: LPCSTR fp = File to search
525: // In: LPCSTR szString = Keyword to look for
526: // In: int szDefault = Default value to to return if not found
527: // Out: int = Value found
528: //===========================================================================
529:
530: int ReadInt(LPCSTR fp, LPCSTR szString, int szDefault)
531: {
532: return pSettings->GetInt(fp, NULL, szString, szDefault);
533: }
534:
535: //===========================================================================
536: // Function: ReadString
537: // Purpose: Searches given file for string
538: // In: LPCSTR fp = File to search
539: // In: LPCSTR szString = String to return value of
540: // In: LPSTR szDefault = Pointer to value to return if not found
541: // Out: LPSTR = Pointer to found string
542: //===========================================================================
543:
544: LPSTR ReadString(LPCSTR fp, LPCSTR szString, LPSTR szDefault)
545: {
546: return pSettings->GetString(fp, NULL, szString, szDefault);
547: }
548:
549: //===========================================================================
550: // Function: ReadColor
551: // Purpose: Read's a value in the given file and outputs the return as a COLORREF
552: // In: LPCSTR fp = File to search
553: // In: LPCSTR szString = String to return value of
554: // In: LPCSTR szDefault = String to parse and return if not found
555: // Out: COLORREF = Value returned from file (parsed)
556: //===========================================================================
557:
558: COLORREF ReadColor(LPCSTR fp, LPCSTR szString, LPCSTR szDefault)
559: {
560: return pSettings->GetColor(fp, NULL, szString, szDefault, NULL, false);
561: }
562:
563: //===========================================================================
564: // Function: GetSettingPtr
565: // Purpose: Return a pointer to a setting in the core buffer
566: // In: int index = Setting number = SN_XXX constants in BBApi.h
567: // Out: Pointer to the requested setting
568: //===========================================================================
569:
570: void* GetSettingPtr(int index)
571: {
572: switch (index)
573: {
574: case SN_TOOLBAR : return (void*) pSettings->Toolbar;
575: case SN_TOOLBARBUTTON : return (void*) pSettings->ToolbarButton;
576: case SN_TOOLBARBUTTONP : return (void*) pSettings->ToolbarButtonPressed;
577: case SN_TOOLBARLABEL : return (void*) pSettings->ToolbarLabel;
578: case SN_TOOLBARWINDOWLABEL : return (void*) pSettings->ToolbarWindowLabel;
579: case SN_TOOLBARCLOCK : return (void*) pSettings->ToolbarClock;
580: case SN_MENUTITLE : return (void*) pSettings->MenuTitle;
581: case SN_MENUFRAME : return (void*) pSettings->MenuFrame;
582: case SN_MENUHILITE : return (void*) pSettings->MenuActive;
583:
584: case SN_BORDERWIDTH : return (void*) &pSettings->borderWidth;
585: case SN_BORDERCOLOR : return (void*) &pSettings->borderColor;
586: case SN_BEVELWIDTH : return (void*) &pSettings->bevelWidth;
587:
588: case SN_METRICSUNIX : return (void*) false;
589: case SN_BULLETUNIX : return (void*) false;
590: case SN_ROOTCOMMAND : return (void*) &pSettings->rootCommand;
591:
592: case SN_MENUBULLET : return (void*) &pSettings->menuBullet;
593: case SN_MENUBULLETPOS : return (void*) &pSettings->menuBulletPosition;
594: case SN_FRAMEWIDTH : return (void*) &pSettings->frameWidth;
595: case SN_HANDLEWIDTH : return (void*) &pSettings->handleHeight; // Note: Same index as SN_HANDLEHEIGHT
596:
597: case SN_MENUALPHA : return (void*) &pSettings->menuTransparencyAlpha;
598: case SN_TOOLBARALPHA : return (void*) &pSettings->toolbarTransparencyAlpha;
599:
600: case SN_WINFOCUS_TITLE : return (void*) pSettings->WindowTitleFocus;
601: case SN_WINFOCUS_LABEL : return (void*) pSettings->WindowLabelFocus;
602: case SN_WINFOCUS_HANDLE : return (void*) pSettings->WindowHandleFocus;
603: case SN_WINFOCUS_GRIP : return (void*) pSettings->WindowGripFocus;
604: case SN_WINFOCUS_BUTTON : return (void*) pSettings->WindowButtonFocus;
605: case SN_WINFOCUS_BUTTONP : return (void*) pSettings->WindowButtonPressed;
606:
607: case SN_WINUNFOCUS_TITLE : return (void*) pSettings->WindowTitleUnfocus;
608: case SN_WINUNFOCUS_LABEL : return (void*) pSettings->WindowLabelUnfocus;
609: case SN_WINUNFOCUS_HANDLE : return (void*) pSettings->WindowHandleUnfocus;
610: case SN_WINUNFOCUS_GRIP : return (void*) pSettings->WindowGripUnfocus;
611: case SN_WINUNFOCUS_BUTTON : return (void*) pSettings->WindowButtonUnfocus;
612: /*
613: case SN_WINFOCUS_FRAME_COLOR : return (void*) &pSettings->borderColor;
614: case SN_WINUNFOCUS_FRAME_COLOR : return (void*) &pSettings->borderColor;
615: */
616: case SN_NEWMETRICS : return (void*) false;
617:
618: case SN_ISSTYLE070 : return (void*) true; // ...OK?
619: case SN_SLIT : return (void*) pSettings->Dock;
620:
621: case SN_MENUSEPMARGIN : return (void*) 1; // PLACEHOLDER (for basic API compatibility only)
622: case SN_MENUSEPCOLOR : return (void*) &pSettings->MenuSeparator->Color;
623: case SN_MENUSEPSHADOWCOLOR : return (void*) &pSettings->MenuSeparator->Color; // PLACEHOLDER (for basic API compatibility only)
624: case SN_MENUGRIP : return (void*) pSettings->MenuGrip;
625: }
626:
627: return NULL;
628: }
629:
630: //===========================================================================
631: // Function: Log
632: // Purpose: Appends given line to xoblite.log file
633: // In: LPCSTR des = Value to identify variable
634: // In: LPCSTR line = Outputted line
635: // Out: void = NULL
636: //===========================================================================
637:
638: void Log(LPCSTR des, LPCSTR line)
639: {
640: char date[9], time[9];
641: char tempBuf[MAX_LINE_LENGTH];
642: GetBlackboxPath(tempBuf, sizeof(tempBuf));
643: strcat_s(tempBuf, sizeofArray(tempBuf), "xoblite.log");
644:
645: FILE *f = fopen(tempBuf, "a+");
646: if (f)
647: {
648: _strdate(date);
649: _strtime(time);
650: if (strlen(line)) fprintf(f, "%s %s - %s: %s\n", date, time, des, line);
651: else fprintf(f, "%s %s - %s\n", date, time, des);
652: fclose(f);
653: }
654: else MBoxErrorFile(tempBuf);
655: }
656:
657: //===========================================================================
658: // Function: FileRead
659: // Purpose: Reads a line from the specified file and returns boolean on status
660: // In: FILE *stream = File to parse
661: // In: LPSTR string = Pointer to returned line from the file
662: // Out: bool = Status (true if read, false if not)
663: //===========================================================================
664:
665: bool FileRead(FILE *stream, LPSTR string)
666: {
667: int ch, // Character read from file
668: cnbr; // Index into returned string
669:
670: cnbr = 0; // Start at the beginning...
671: memset(string, ' ', MAX_LINE_LENGTH); // ...and prepare the entire line
672:
673: for (;;)
674: {
675: ch = fgetc(stream); // Get next character from the file...
676:
677: if (ch == '\t') // Jump if the character is a tab...
678: {
679: cnbr = ((cnbr >> 3) << 3) + 8;
680: }
681: // If the character is end of line, end of file, or MS-DOS Ctrl-Z...
682: /*else*/ if ((ch == '\n') || (ch == EOF) || (ch == 26))
683: {
684: string[cnbr] = '\0'; // ...terminate the string...
685: return(ch == '\n' || cnbr); // ...and return true/false
686: }
687: else if (cnbr < MAX_LINE_LENGTH)
688: {
689: // ...otherwise add the character to the output string
690: string[cnbr++] = (char) ch;
691: }
692:
693: // Return in any case if line is too long, the line will be cut into pieces...
694: if (cnbr >= MAX_LINE_LENGTH)
695: {
696: string[MAX_LINE_LENGTH] = '\0';
697: return true;
698: }
699: }
700: }
701:
702: //===========================================================================
703: // Function: ReadNextCommand
704: // Purpose: Reads the next line of the file
705: // In: FILE* = File to be parsed
706: // In: LPSTR = buffer to assign next line to
707: // DWORD = maximum size of line to be outputted
708: // Out: bool = whether there was a next line to parse
709: //===========================================================================
710:
711: static char szTempBuffer[MAX_LINE_LENGTH];
712:
713: bool ReadNextCommand(FILE *f, LPSTR szBuffer, DWORD dwLength)
714: {
715: if (!f) return false;
716:
717: while (FileRead(f, szTempBuffer))
718: {
719: while (isspace(*szTempBuffer) && *szTempBuffer) memmove(szTempBuffer, szTempBuffer+1, strnlen_s(szTempBuffer, sizeofArray(szTempBuffer))); // Clean out initial spaces...
720:
721: if (szTempBuffer[0] && szTempBuffer[0] != '#' && szTempBuffer != 0 && szTempBuffer[0] != '!') // Check for comment lines...
722: {
723: strncpy(szBuffer, szTempBuffer, dwLength);
724: return true;
725: }
726:
727: if (!strcmp(szTempBuffer, "[end]")) strncpy(szBuffer, szTempBuffer, dwLength);
728: }
729:
730: return false;
731: }
732:
733: //===========================================================================
734: // Function: GetConfigFilePath
735: // Purpose: Internal support function to allow backwards compatibility
736: // with fallback xoblite.rc -> blackbox.rc/extensions.rc
737: //===========================================================================
738:
739: bool GetConfigFilePath(LPSTR filePath, LPCSTR setPath, LPCSTR checkName1, LPCSTR checkName2)
740: {
741: if (setPath != NULL)
742: {
743: strcpy(filePath, setPath);
744: if (strchr(filePath, '\"')) StrRemoveEncap(filePath);
745: }
746:
747: else if (strlen(filePath) == 0) // We only need to do this once!
748: {
749: // Check for the file specified by checkName1 in the
750: // Blackbox and $UserAppData$\Blackbox directories...
751: strcpy(filePath, ConfigFileExists(checkName1, NULL));
752: if (!_stricmp(filePath, ""))
753: {
754: if (checkName2 != NULL)
755: {
756: // If not found, check for the file specified
757: // by checkName2 in the same directories...
758: strcpy(filePath, ConfigFileExists(checkName2, NULL));
759: if (!_stricmp(filePath, "")) return false;
760: }
761: else return false;
762: }
763: }
764:
765: return true;
766: }
767:
768: //===========================================================================
769: // Function: ConfigFileExists
770: // Purpose: Look for a config file in the Blackbox, UserAppData and
771: // (optionally) plugin directories
772: // In: LPCSTR = filename to look for, LPCSTR = plugin directory or NULL
773: // Out: LPCSTR = full path to file, or "" if not found
774: //===========================================================================
775:
776: LPCSTR ConfigFileExists(LPCSTR filename, LPCSTR pluginDir)
777: {
778: // First we look for the file in the $UserAppData$\Blackbox directory
779: // (previously C:\Documents and Settings\username\Application Data\Blackbox ,
780: // nowadays more often C:\Users\username\AppData\Blackbox ),
781: // i.e. allowing per-user specific configuration for a given file:
782: strcpy_s(tempBuf, sizeofArray(tempBuf), pSettings->SF_userAppData);
783: strcat_s(tempBuf, sizeofArray(tempBuf), "\\Blackbox\\");
784: strcat_s(tempBuf, sizeofArray(tempBuf), filename);
785: if (!FileExists(tempBuf))
786: {
787: // If not found, we check the root of the current theme folder,
788: // i.e. allowing per theme configuration data while re-using
789: // shared plugin .dll's located in another folder for all themes:
790: sprintf_s(tempBuf, sizeofArray(tempBuf), "%s\\%s", pSettings->SF_currentThemePath, filename);
791: if (FileExists(tempBuf)) return tempBuf;
792:
793: // If still not found, and if a pluginDir was specified,
794: // we look for the file in this directory... (note: this would typically be the same
795: // folder as the plugin .dll, i.e. not allowing plugin re-use across themes like above)
796: if (pluginDir != NULL)
797: {
798: strcpy_s(tempBuf, sizeofArray(tempBuf), pluginDir);
799: strcat_s(tempBuf, sizeofArray(tempBuf), filename);
800: if (FileExists(tempBuf)) return tempBuf;
801: }
802:
803: // Finally, if *still* not found, we look for the file in the Blackbox directory...
804: GetBlackboxPath(tempBuf, sizeof(tempBuf));
805: strcat_s(tempBuf, sizeofArray(tempBuf), filename);
806: if (!FileExists(tempBuf)) strcpy_s(tempBuf, sizeofArray(tempBuf), "");
807: }
808:
809: return tempBuf;
810: }
811:
812: //===========================================================================
813: // Function: FileExists
814: // Purpose: Checks if a file exists
815: // In: LPCSTR = file to look for
816: // Out: bool = whether found or not
817: //===========================================================================
818:
819: bool FileExists(LPCSTR szFileName)
820: {
821: HANDLE handle;
822: WIN32_FIND_DATA findData;
823:
824: handle = FindFirstFile(szFileName, &findData);
825: if (handle != INVALID_HANDLE_VALUE)
826: {
827: FindClose(handle);
828: if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
829: return true;
830: }
831:
832: return false;
833: }
834:
835: //===========================================================================
836: // Function: FolderExists
837: // Purpose: Checks if a folder exists
838: // In: LPCSTR = Folder to look for
839: // Out: bool = Whether found or not
840: //===========================================================================
841:
842: bool FolderExists(LPCSTR szFolderPath)
843: {
844: HANDLE handle;
845: WIN32_FIND_DATA findData;
846:
847: handle = FindFirstFile(szFolderPath, &findData);
848: if (handle != INVALID_HANDLE_VALUE)
849: {
850: FindClose(handle);
851: if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
852: return true;
853: }
854:
855: return false;
856: }
857:
858: //===========================================================================
859: // Function: bbrcPath
860: // Purpose: Get or set the path to the xoblite.rc/blackbox.rc to be used
861: //===========================================================================
862:
863: LPCSTR bbrcPath(LPCSTR other)
864: {
865: // Check for xoblite.rc/blackbox.rc in the main Blackbox and $UserAppData$\Blackbox directories...
866: if (!GetConfigFilePath(pSettings->bbrcFile, other, "xoblite.rc", "blackbox.rc"))
867: {
868: // If still not found, we create a new default
869: // blackbox.rc (legacy fallback!) in the main Blackbox directory...
870: pSettings->WriteDefaultRCSettings();
871: }
872:
873: return pSettings->bbrcFile;
874: }
875:
876: //===========================================================================
877: // Function: extensionsrcPath
878: // Purpose: Get or set the path to the xoblite.rc/extensions.rc to be used
879: //===========================================================================
880:
881: LPCSTR extensionsrcPath(LPCSTR other)
882: {
883: // Check for xoblite.rc/extensions.rc in the main Blackbox and $UserAppData$\Blackbox directories...
884: if (!GetConfigFilePath(pSettings->xobrcFile, other, "xoblite.rc", "extensions.rc"))
885: {
886: // If still not found, set the default path
887: // -> xoblite.rc in the main Blackbox directory...
888: GetBlackboxPath(pSettings->xobrcFile, sizeof(pSettings->xobrcFile));
889: strcat_s(pSettings->xobrcFile, sizeofArray(pSettings->xobrcFile), "xoblite.rc");
890: }
891:
892: return pSettings->xobrcFile;
893: }
894:
895: //===========================================================================
896: // Function: plugrcPath
897: // Purpose: Get or set the path to the plugins.rc to be used
898: //===========================================================================
899:
900: LPCSTR plugrcPath(LPCSTR other)
901: {
902: /*
903: // Check for plugins.rc in the Blackbox and $UserAppData$\Blackbox directories...
904: if (!GetConfigFilePath(pSettings->pluginsFile, other, "plugins.rc", NULL))
905: {
906: // If still not found, set the default path
907: // -> plugins.rc in the main Blackbox directory...
908: GetBlackboxPath(pSettings->pluginsFile, sizeof(pSettings->pluginsFile));
909: strcat_s(pSettings->pluginsFile, sizeofArray(pSettings->pluginsFile), "plugins.rc");
910: }
911: */
912: return pSettings->pluginsFile;
913: }
914:
915: //===========================================================================
916: // Function: menuPath
917: // Purpose: Get or set the path to the menu.rc to be used
918: //===========================================================================
919:
920: LPCSTR menuPath(LPCSTR other)
921: {
922: if (other != NULL)
923: {
924: strcpy_s(pSettings->menuFile, sizeofArray(pSettings->menuFile), other);
925: if (strchr(pSettings->menuFile, '\"')) StrRemoveEncap(pSettings->menuFile);
926: if (strchr(pSettings->menuFile, '$')) ReplaceShellFolders(pSettings->menuFile);
927: if (strchr(pSettings->menuFile, '%')) ReplaceEnvVars(pSettings->menuFile);
928:
929: // If the full path to the menu file is specified and it is in a subfolder
930: // to the Blackbox folder, extract the relative path to the menu file
931: // -> full path with the Blackbox folder replaced by an environment variable.
932: // Example: "C:\Blackbox\menu.rc" becomes "$Blackbox$\menu.rc"
933: // This way the Blackbox folder can be moved, and the menu path will still work! :D
934:
935: if (IsInString(pSettings->menuFile, pSettings->SF_blackboxPath))
936: {
937: char relativePath[MAX_LINE_LENGTH];
938: strcpy_s(relativePath, sizeofArray(relativePath), "$Blackbox$");
939: strcat_s(relativePath, sizeofArray(relativePath), &pSettings->menuFile[(strnlen_s(pSettings->SF_blackboxPath, sizeofArray(pSettings->SF_blackboxPath)))]);
940: WriteString(pSettings->xobrcDefaultFile, "xoblite.menuFile:", relativePath);
941: }
942: else if (IsInString(pSettings->menuFile, pSettings->SF_userAppData))
943: {
944: char relativePath[MAX_LINE_LENGTH];
945: strcpy_s(relativePath, sizeofArray(relativePath), "$UserAppData$");
946: strcat_s(relativePath, sizeofArray(relativePath), &pSettings->menuFile[(strnlen_s(pSettings->SF_userAppData, sizeofArray(pSettings->SF_userAppData)))]);
947: WriteString(pSettings->xobrcDefaultFile, "xoblite.menuFile:", relativePath);
948: }
949: else WriteString(pSettings->xobrcDefaultFile, "xoblite.menuFile:", pSettings->menuFile);
950: }
951:
952: return pSettings->menuFile;
953: }
954:
955: //===========================================================================
956: // Function: stylePath
957: // Purpose: Get or set the path to the style file to be used
958: //===========================================================================
959:
960: LPCSTR stylePath(LPCSTR other)
961: {
962: if (other != NULL)
963: {
964: strcpy_s(pSettings->styleFile, sizeofArray(pSettings->styleFile), other);
965: if (strchr(pSettings->styleFile, '\"')) StrRemoveEncap(pSettings->styleFile);
966: if (strchr(pSettings->styleFile, '$')) ReplaceShellFolders(pSettings->styleFile);
967: if (strchr(pSettings->styleFile, '%')) ReplaceEnvVars(pSettings->styleFile);
968:
969: // If the full path to the style is specified and it is in a subfolder
970: // to the Blackbox folder, extract the relative path to the style
971: // -> full path with the Blackbox folder replaced by an environment variable.
972: // Example: "C:\Blackbox\styles\charcoal" becomes "$Blackbox$\styles\charcoal"
973: // This way the Blackbox folder can be moved, and the style path will still work! :D
974:
975: if (!pSettings->usingDefaultTheme && IsInString(pSettings->styleFile, pSettings->SF_currentThemePath))
976: {
977: char relativePath[MAX_LINE_LENGTH];
978: strcpy_s(relativePath, sizeofArray(relativePath), "$CurrentTheme$");
979: strcat_s(relativePath, sizeofArray(relativePath), &pSettings->styleFile[(strnlen_s(pSettings->SF_currentThemePath, sizeofArray(pSettings->SF_currentThemePath)))]);
980: WriteString(pSettings->xobrcFile, "xoblite.styleFile:", relativePath);
981: }
982: else if (IsInString(pSettings->styleFile, pSettings->SF_blackboxPath))
983: {
984: char relativePath[MAX_LINE_LENGTH];
985: strcpy_s(relativePath, sizeofArray(relativePath), "$Blackbox$");
986: strcat_s(relativePath, sizeofArray(relativePath), &pSettings->styleFile[(strnlen_s(pSettings->SF_blackboxPath, sizeofArray(pSettings->SF_blackboxPath)))]);
987: WriteString(pSettings->xobrcFile, "xoblite.styleFile:", relativePath);
988: }
989: else WriteString(pSettings->xobrcFile, "xoblite.styleFile:", pSettings->styleFile);
990: }
991:
992: return pSettings->styleFile;
993: }
994:
995: //===========================================================================
996: // Function: GetBlackboxEditor
997: // Purpose: Returns the path to the preferred editor as defined in ext.rc
998: // In: LPSTR = string to copy path to
999: // Out: void
1000: //===========================================================================
1001:
1002: void GetBlackboxEditor(LPSTR editor)
1003: {
1004: strncpy_s(editor, MAX_PATH, pSettings->preferredEditor, _TRUNCATE); // Yes, this is still unsafe... (legacy API function)
1005: }
1006:
1007: //===========================================================================
1008: // Function: ParseLiteralColor
1009: // Purpose: Parses a given literal colour and returns the hex value
1010: // In: LPCSTR = color to parse (eg. "black", "white")
1011: // Out: COLORREF (DWORD) of rgb value
1012: // (old)Out: LPCSTR = literal hex value
1013: //===========================================================================
1014:
1015: COLORREF ParseLiteralColor(LPCSTR colour)
1016: {
1017: int i = strchr(colour, ' ') - colour;
1018: while (i > 0)
1019: {
1020: memmove ( (VOID*) (colour + i), (VOID*) (colour + i + 1), strlen (colour) - i );
1021: i = strchr(colour, ' ') - colour;
1022: }
1023:
1024: //====================
1025:
1026: if (!_strnicmp(colour, "gray", 4) || !_strnicmp(colour, "grey", 4))
1027: {
1028: i = strlen(colour);
1029: if (i > 5)
1030: {
1031: float tmp = (float)(2.55 * atoi(colour+4));
1032: i = (int)(tmp + .5);
1033: if (i < (int)tmp) i = (int)tmp;
1034: return RGB(i,i,i);
1035: }
1036: else return RGB(80,80,80);
1037: }
1038:
1039: char firstCharacter = colour[0];
1040:
1041: //====================
1042:
1043: switch (colour[0])
1044: {
1045: case 'a': //====================
1046: {
1047: if (! _stricmp(colour, "aliceblue")) return RGB(240,248,255);
1048: else if (! _stricmp(colour, "antiquewhite")) return RGB(250,235,215);
1049: else if (! _stricmp(colour, "aquamarine")) return RGB(127,255,212);
1050: else if (! _stricmp(colour, "azure")) return RGB(240,255,255);
1051: /*
1052: else if (! _stricmp(colour, "antiquewhite1")) return RGB(255,239,219);
1053: else if (! _stricmp(colour, "antiquewhite2")) return RGB(238,223,204);
1054: else if (! _stricmp(colour, "antiquewhite3")) return RGB(205,192,176);
1055: else if (! _stricmp(colour, "antiquewhite4")) return RGB(139,131,120);
1056: else if (! _stricmp(colour, "aquamarine1")) return RGB(127,255,212);
1057: else if (! _stricmp(colour, "aquamarine2")) return RGB(118,238,198);
1058: else if (! _stricmp(colour, "aquamarine3")) return RGB(102,205,170);
1059: else if (! _stricmp(colour, "aquamarine4")) return RGB(69,139,116);
1060: else if (! _stricmp(colour, "azure1")) return RGB(240,255,255);
1061: else if (! _stricmp(colour, "azure2")) return RGB(224,238,238);
1062: else if (! _stricmp(colour, "azure3")) return RGB(193,205,205);
1063: else if (! _stricmp(colour, "azure4")) return RGB(131,139,139);
1064: */
1065: }
1066: case 'b': //====================
1067: {
1068: if (! _stricmp(colour, "beige")) return RGB(245,245,220);
1069: else if (! _stricmp(colour, "bisque")) return RGB(255,228,196);
1070: else if (! _stricmp(colour, "black")) return RGB(0,0,0);
1071: else if (! _stricmp(colour, "blanchedalmond")) return RGB(255,235,205);
1072: else if (! _stricmp(colour, "blue")) return RGB(0,0,255);
1073: else if (! _stricmp(colour, "blueviolet")) return RGB(138,43,226);
1074: else if (! _stricmp(colour, "brown")) return RGB(165,42,42);
1075: else if (! _stricmp(colour, "burlywood")) return RGB(222,184,135);
1076: /*
1077: else if (! _stricmp(colour, "bisque1")) return RGB(255,228,196);
1078: else if (! _stricmp(colour, "bisque2")) return RGB(238,213,183);
1079: else if (! _stricmp(colour, "bisque3")) return RGB(205,183,158);
1080: else if (! _stricmp(colour, "bisque4")) return RGB(139,125,107);
1081: else if (! _stricmp(colour, "blue1")) return RGB(0,0,255);
1082: else if (! _stricmp(colour, "blue2")) return RGB(0,0,238);
1083: else if (! _stricmp(colour, "blue3")) return RGB(0,0,205);
1084: else if (! _stricmp(colour, "blue4")) return RGB(0,0,139);
1085: else if (! _stricmp(colour, "brown1")) return RGB(255,64,64);
1086: else if (! _stricmp(colour, "brown2")) return RGB(238,59,59);
1087: else if (! _stricmp(colour, "brown3")) return RGB(205,51,51);
1088: else if (! _stricmp(colour, "brown4")) return RGB(139,35,35);
1089: else if (! _stricmp(colour, "burlywood1")) return RGB(255,211,155);
1090: else if (! _stricmp(colour, "burlywood2")) return RGB(238,197,145);
1091: else if (! _stricmp(colour, "burlywood3")) return RGB(205,170,125);
1092: else if (! _stricmp(colour, "burlywood4")) return RGB(139,115,85);
1093: */
1094: }
1095: case 'c': //====================
1096: {
1097: if (! _stricmp(colour, "cadetblue")) return RGB(95,158,160);
1098: else if (! _stricmp(colour, "chartreuse")) return RGB(127,255,0);
1099: else if (! _stricmp(colour, "chocolate")) return RGB(210,105,30);
1100: else if (! _stricmp(colour, "coral")) return RGB(255,127,80);
1101: else if (! _stricmp(colour, "cornflowerblue")) return RGB(100,149,237);
1102: else if (! _stricmp(colour, "cornsilk")) return RGB(255,248,220);
1103: else if (! _stricmp(colour, "cyan")) return RGB(0,255,255);
1104: /*
1105: else if (! _stricmp(colour, "cadetblue1")) return RGB(152,245,255);
1106: else if (! _stricmp(colour, "cadetblue2")) return RGB(142,229,238);
1107: else if (! _stricmp(colour, "cadetblue3")) return RGB(122,197,205);
1108: else if (! _stricmp(colour, "cadetblue4")) return RGB(83,134,139);
1109: else if (! _stricmp(colour, "chartreuse1")) return RGB(127,255,0);
1110: else if (! _stricmp(colour, "chartreuse2")) return RGB(118,238,0);
1111: else if (! _stricmp(colour, "chartreuse3")) return RGB(102,205,0);
1112: else if (! _stricmp(colour, "chartreuse4")) return RGB(69,139,0);
1113: else if (! _stricmp(colour, "chocolate1")) return RGB(255,127,36);
1114: else if (! _stricmp(colour, "chocolate2")) return RGB(238,118,33);
1115: else if (! _stricmp(colour, "chocolate3")) return RGB(205,102,29);
1116: else if (! _stricmp(colour, "chocolate4")) return RGB(139,69,19);
1117: else if (! _stricmp(colour, "coral1")) return RGB(255,114,86);
1118: else if (! _stricmp(colour, "coral2")) return RGB(238,106,80);
1119: else if (! _stricmp(colour, "coral3")) return RGB(205,91,69);
1120: else if (! _stricmp(colour, "coral4")) return RGB(139,62,47);
1121: else if (! _stricmp(colour, "cornsilk1")) return RGB(255,248,220);
1122: else if (! _stricmp(colour, "cornsilk2")) return RGB(238,232,205);
1123: else if (! _stricmp(colour, "cornsilk3")) return RGB(205,200,177);
1124: else if (! _stricmp(colour, "cornsilk4")) return RGB(139,136,120);
1125: else if (! _stricmp(colour, "cyan1")) return RGB(0,255,255);
1126: else if (! _stricmp(colour, "cyan2")) return RGB(0,238,238);
1127: else if (! _stricmp(colour, "cyan3")) return RGB(0,205,205);
1128: else if (! _stricmp(colour, "cyan4")) return RGB(0,139,139);
1129: */
1130: }
1131: case 'd': //====================
1132: {
1133: if (! _stricmp(colour, "darkblue")) return RGB(0,0,139);
1134: else if (! _stricmp(colour, "darkcyan")) return RGB(0,139,139);
1135: else if (! _stricmp(colour, "darkgoldenrod")) return RGB(184,134,11);
1136: else if (! _stricmp(colour, "darkgray")) return RGB(169,169,169);
1137: else if (! _stricmp(colour, "darkgreen")) return RGB(0,100,0);
1138: else if (! _stricmp(colour, "darkgrey")) return RGB(169,169,169);
1139: else if (! _stricmp(colour, "darkkhaki")) return RGB(189,183,107);
1140: else if (! _stricmp(colour, "darkmagenta")) return RGB(139,0,139);
1141: else if (! _stricmp(colour, "darkolivegreen")) return RGB(85,107,47);
1142: else if (! _stricmp(colour, "darkorange")) return RGB(255,140,0);
1143: else if (! _stricmp(colour, "darkorchid")) return RGB(153,50,204);
1144: else if (! _stricmp(colour, "darkred")) return RGB(139,0,0);
1145: else if (! _stricmp(colour, "darksalmon")) return RGB(233,150,122);
1146: else if (! _stricmp(colour, "darkseagreen")) return RGB(143,188,143);
1147: else if (! _stricmp(colour, "darkslateblue")) return RGB(72,61,139);
1148: else if (! _stricmp(colour, "darkslategray")) return RGB(47,79,79);
1149: else if (! _stricmp(colour, "darkslategrey")) return RGB(47,79,79);
1150: else if (! _stricmp(colour, "darkturquoise")) return RGB(0,206,209);
1151: else if (! _stricmp(colour, "darkviolet")) return RGB(148,0,211);
1152: else if (! _stricmp(colour, "deeppink")) return RGB(255,20,147);
1153: else if (! _stricmp(colour, "deepskyblue")) return RGB(0,191,255);
1154: else if (! _stricmp(colour, "dimgray")) return RGB(105,105,105);
1155: else if (! _stricmp(colour, "dimgrey")) return RGB(105,105,105);
1156: else if (! _stricmp(colour, "dodgerblue")) return RGB(30,144,255);
1157: /*
1158: else if (! _stricmp(colour, "darkgoldenrod1")) return RGB(255,185,15);
1159: else if (! _stricmp(colour, "darkgoldenrod2")) return RGB(238,173,14);
1160: else if (! _stricmp(colour, "darkgoldenrod3")) return RGB(205,149,12);
1161: else if (! _stricmp(colour, "darkgoldenrod4")) return RGB(139,101,8);
1162: else if (! _stricmp(colour, "darkolivegreen1")) return RGB(202,255,112);
1163: else if (! _stricmp(colour, "darkolivegreen2")) return RGB(188,238,104);
1164: else if (! _stricmp(colour, "darkolivegreen3")) return RGB(162,205,90);
1165: else if (! _stricmp(colour, "darkolivegreen4")) return RGB(110,139,61);
1166: else if (! _stricmp(colour, "darkorange1")) return RGB(255,127,0);
1167: else if (! _stricmp(colour, "darkorange2")) return RGB(238,118,0);
1168: else if (! _stricmp(colour, "darkorange3")) return RGB(205,102,0);
1169: else if (! _stricmp(colour, "darkorange4")) return RGB(139,69,0);
1170: else if (! _stricmp(colour, "darkorchid1")) return RGB(191,62,255);
1171: else if (! _stricmp(colour, "darkorchid2")) return RGB(178,58,238);
1172: else if (! _stricmp(colour, "darkorchid3")) return RGB(154,50,205);
1173: else if (! _stricmp(colour, "darkorchid4")) return RGB(104,34,139);
1174: else if (! _stricmp(colour, "darkseagreen1")) return RGB(193,255,193);
1175: else if (! _stricmp(colour, "darkseagreen2")) return RGB(180,238,180);
1176: else if (! _stricmp(colour, "darkseagreen3")) return RGB(155,205,155);
1177: else if (! _stricmp(colour, "darkseagreen4")) return RGB(105,139,105);
1178: else if (! _stricmp(colour, "deeppink1")) return RGB(255,20,147);
1179: else if (! _stricmp(colour, "deeppink2")) return RGB(238,18,137);
1180: else if (! _stricmp(colour, "deeppink3")) return RGB(205,16,118);
1181: else if (! _stricmp(colour, "deeppink4")) return RGB(139,10,80);
1182: else if (! _stricmp(colour, "deepskyblue1")) return RGB(0,191,255);
1183: else if (! _stricmp(colour, "deepskyblue2")) return RGB(0,178,238);
1184: else if (! _stricmp(colour, "deepskyblue3")) return RGB(0,154,205);
1185: else if (! _stricmp(colour, "deepskyblue4")) return RGB(0,104,139);
1186: else if (! _stricmp(colour, "darkslategray1")) return RGB(151,255,255);
1187: else if (! _stricmp(colour, "darkslategray2")) return RGB(141,238,238);
1188: else if (! _stricmp(colour, "darkslategray3")) return RGB(121,205,205);
1189: else if (! _stricmp(colour, "darkslategray4")) return RGB(82,139,139);
1190: else if (! _stricmp(colour, "dodgerblue1")) return RGB(30,144,255);
1191: else if (! _stricmp(colour, "dodgerblue2")) return RGB(28,134,238);
1192: else if (! _stricmp(colour, "dodgerblue3")) return RGB(24,116,205);
1193: else if (! _stricmp(colour, "dodgerblue4")) return RGB(16,78,139);
1194: */
1195: }
1196: case 'f': //====================
1197: {
1198: if (! _stricmp(colour, "firebrick")) return RGB(178,34,34);
1199: else if (! _stricmp(colour, "floralwhite")) return RGB(255,250,240);
1200: else if (! _stricmp(colour, "forestgreen")) return RGB(34,139,34);
1201: /*
1202: else if (! _stricmp(colour, "firebrick1")) return RGB(255,48,48);
1203: else if (! _stricmp(colour, "firebrick2")) return RGB(238,44,44);
1204: else if (! _stricmp(colour, "firebrick3")) return RGB(205,38,38);
1205: else if (! _stricmp(colour, "firebrick4")) return RGB(139,26,26);
1206: */
1207: }
1208: case 'g': //====================
1209: {
1210: if (! _stricmp(colour, "gainsboro")) return RGB(220,220,220);
1211: else if (! _stricmp(colour, "ghostwhite")) return RGB(248,248,255);
1212: else if (! _stricmp(colour, "gold")) return RGB(255,215,0);
1213: else if (! _stricmp(colour, "goldenrod")) return RGB(218,165,32);
1214: else if (! _stricmp(colour, "gray")) return RGB(190,190,190);
1215: else if (! _stricmp(colour, "green")) return RGB(0,255,0);
1216: else if (! _stricmp(colour, "greenyellow")) return RGB(173,255,47);
1217: else if (! _stricmp(colour, "grey")) return RGB(190,190,190);
1218: /*
1219: else if (! _stricmp(colour, "gold1")) return RGB(255,215,0);
1220: else if (! _stricmp(colour, "gold2")) return RGB(238,201,0);
1221: else if (! _stricmp(colour, "gold3")) return RGB(205,173,0);
1222: else if (! _stricmp(colour, "gold4")) return RGB(139,117,0);
1223: else if (! _stricmp(colour, "goldenrod1")) return RGB(255,193,37);
1224: else if (! _stricmp(colour, "goldenrod2")) return RGB(238,180,34);
1225: else if (! _stricmp(colour, "goldenrod3")) return RGB(205,155,29);
1226: else if (! _stricmp(colour, "goldenrod4")) return RGB(139,105,20);
1227: else if (! _stricmp(colour, "green1")) return RGB(0,255,0);
1228: else if (! _stricmp(colour, "green2")) return RGB(0,238,0);
1229: else if (! _stricmp(colour, "green3")) return RGB(0,205,0);
1230: else if (! _stricmp(colour, "green4")) return RGB(0,139,0);
1231: */
1232: }
1233: case 'h': //====================
1234: {
1235: if (! _stricmp(colour, "honeydew")) return RGB(240,255,240);
1236: else if (! _stricmp(colour, "hotpink")) return RGB(255,105,180);
1237: /*
1238: else if (! _stricmp(colour, "honeydew1")) return RGB(240,255,240);
1239: else if (! _stricmp(colour, "honeydew2")) return RGB(224,238,224);
1240: else if (! _stricmp(colour, "honeydew3")) return RGB(193,205,193);
1241: else if (! _stricmp(colour, "honeydew4")) return RGB(131,139,131);
1242: else if (! _stricmp(colour, "hotpink1")) return RGB(255,110,180);
1243: else if (! _stricmp(colour, "hotpink2")) return RGB(238,106,167);
1244: else if (! _stricmp(colour, "hotpink3")) return RGB(205,96,144);
1245: else if (! _stricmp(colour, "hotpink4")) return RGB(139,58,98);
1246: */
1247: }
1248: case 'i': //====================
1249: {
1250: if (! _stricmp(colour, "indianred")) return RGB(205,92,92);
1251: else if (! _stricmp(colour, "ivory")) return RGB(255,255,240);
1252: /*
1253: else if (! _stricmp(colour, "indianred1")) return RGB(255,106,106);
1254: else if (! _stricmp(colour, "indianred2")) return RGB(238,99,99);
1255: else if (! _stricmp(colour, "indianred3")) return RGB(205,85,85);
1256: else if (! _stricmp(colour, "indianred4")) return RGB(139,58,58);
1257: else if (! _stricmp(colour, "ivory1")) return RGB(255,255,240);
1258: else if (! _stricmp(colour, "ivory2")) return RGB(238,238,224);
1259: else if (! _stricmp(colour, "ivory3")) return RGB(205,205,193);
1260: else if (! _stricmp(colour, "ivory4")) return RGB(139,139,131);
1261: */
1262: }
1263: case 'k': //====================
1264: {
1265: if (! _stricmp(colour, "khaki")) return RGB(240,230,140);
1266: /*
1267: else if (! _stricmp(colour, "khaki1")) return RGB(255,246,143);
1268: else if (! _stricmp(colour, "khaki2")) return RGB(238,230,133);
1269: else if (! _stricmp(colour, "khaki3")) return RGB(205,198,115);
1270: else if (! _stricmp(colour, "khaki4")) return RGB(139,134,78);
1271: */
1272: }
1273: case 'l': //====================
1274: {
1275: if (! _stricmp(colour, "lavender")) return RGB(230,230,250);
1276: else if (! _stricmp(colour, "lavenderblush")) return RGB(255,240,245);
1277: else if (! _stricmp(colour, "lawngreen")) return RGB(124,252,0);
1278: else if (! _stricmp(colour, "lemonchiffon")) return RGB(255,250,205);
1279: else if (! _stricmp(colour, "lightblue")) return RGB(173,216,230);
1280: else if (! _stricmp(colour, "lightcoral")) return RGB(240,128,128);
1281: else if (! _stricmp(colour, "lightcyan")) return RGB(224,255,255);
1282: else if (! _stricmp(colour, "lightgoldenrod")) return RGB(238,221,130);
1283: else if (! _stricmp(colour, "lightgoldenrodyellow")) return RGB(250,250,210);
1284: else if (! _stricmp(colour, "lightgray")) return RGB(211,211,211);
1285: else if (! _stricmp(colour, "lightgreen")) return RGB(144,238,144);
1286: else if (! _stricmp(colour, "lightgrey")) return RGB(211,211,211);
1287: else if (! _stricmp(colour, "lightpink")) return RGB(255,182,193);
1288: else if (! _stricmp(colour, "lightsalmon")) return RGB(255,160,122);
1289: else if (! _stricmp(colour, "lightseagreen")) return RGB(32,178,170);
1290: else if (! _stricmp(colour, "lightskyblue")) return RGB(135,206,250);
1291: else if (! _stricmp(colour, "lightslateblue")) return RGB(132,112,255);
1292: else if (! _stricmp(colour, "lightslategray")) return RGB(119,136,153);
1293: else if (! _stricmp(colour, "lightslategrey")) return RGB(119,136,153);
1294: else if (! _stricmp(colour, "lightsteelblue")) return RGB(176,196,222);
1295: else if (! _stricmp(colour, "lightyellow")) return RGB(255,255,224);
1296: else if (! _stricmp(colour, "limegreen")) return RGB(50,205,50);
1297: else if (! _stricmp(colour, "linen")) return RGB(250,240,230);
1298: /*
1299: else if (! _stricmp(colour, "lavenderblush1")) return RGB(255,240,245);
1300: else if (! _stricmp(colour, "lavenderblush2")) return RGB(238,224,229);
1301: else if (! _stricmp(colour, "lavenderblush3")) return RGB(205,193,197);
1302: else if (! _stricmp(colour, "lavenderblush4")) return RGB(139,131,134);
1303: else if (! _stricmp(colour, "lemonchiffon1")) return RGB(255,250,205);
1304: else if (! _stricmp(colour, "lemonchiffon2")) return RGB(238,233,191);
1305: else if (! _stricmp(colour, "lemonchiffon3")) return RGB(205,201,165);
1306: else if (! _stricmp(colour, "lemonchiffon4")) return RGB(139,137,112);
1307: else if (! _stricmp(colour, "lightblue1")) return RGB(191,239,255);
1308: else if (! _stricmp(colour, "lightblue2")) return RGB(178,223,238);
1309: else if (! _stricmp(colour, "lightblue3")) return RGB(154,192,205);
1310: else if (! _stricmp(colour, "lightblue4")) return RGB(104,131,139);
1311: else if (! _stricmp(colour, "lightcyan1")) return RGB(224,255,255);
1312: else if (! _stricmp(colour, "lightcyan2")) return RGB(209,238,238);
1313: else if (! _stricmp(colour, "lightcyan3")) return RGB(180,205,205);
1314: else if (! _stricmp(colour, "lightcyan4")) return RGB(122,139,139);
1315: else if (! _stricmp(colour, "lightgoldenrod1")) return RGB(255,236,139);
1316: else if (! _stricmp(colour, "lightgoldenrod2")) return RGB(238,220,130);
1317: else if (! _stricmp(colour, "lightgoldenrod3")) return RGB(205,190,112);
1318: else if (! _stricmp(colour, "lightgoldenrod4")) return RGB(139,129,76);
1319: else if (! _stricmp(colour, "lightpink1")) return RGB(255,174,185);
1320: else if (! _stricmp(colour, "lightpink2")) return RGB(238,162,173);
1321: else if (! _stricmp(colour, "lightpink3")) return RGB(205,140,149);
1322: else if (! _stricmp(colour, "lightpink4")) return RGB(139,95,101);
1323: else if (! _stricmp(colour, "lightsalmon1")) return RGB(255,160,122);
1324: else if (! _stricmp(colour, "lightsalmon2")) return RGB(238,149,114);
1325: else if (! _stricmp(colour, "lightsalmon3")) return RGB(205,129,98);
1326: else if (! _stricmp(colour, "lightsalmon4")) return RGB(139,87,66);
1327: else if (! _stricmp(colour, "lightskyblue1")) return RGB(176,226,255);
1328: else if (! _stricmp(colour, "lightskyblue2")) return RGB(164,211,238);
1329: else if (! _stricmp(colour, "lightskyblue3")) return RGB(141,182,205);
1330: else if (! _stricmp(colour, "lightskyblue4")) return RGB(96,123,139);
1331: else if (! _stricmp(colour, "lightsteelblue1")) return RGB(202,225,255);
1332: else if (! _stricmp(colour, "lightsteelblue2")) return RGB(188,210,238);
1333: else if (! _stricmp(colour, "lightsteelblue3")) return RGB(162,181,205);
1334: else if (! _stricmp(colour, "lightsteelblue4")) return RGB(110,123,139);
1335: else if (! _stricmp(colour, "lightyellow1")) return RGB(255,255,224);
1336: else if (! _stricmp(colour, "lightyellow2")) return RGB(238,238,209);
1337: else if (! _stricmp(colour, "lightyellow3")) return RGB(205,205,180);
1338: else if (! _stricmp(colour, "lightyellow4")) return RGB(139,139,122);
1339: */
1340: }
1341: case 'm': //====================
1342: {
1343: if (! _stricmp(colour, "magenta")) return RGB(255,0,255);
1344: else if (! _stricmp(colour, "maroon")) return RGB(176,48,96);
1345: else if (! _stricmp(colour, "mediumaquamarine")) return RGB(102,205,170);
1346: else if (! _stricmp(colour, "mediumblue")) return RGB(0,0,205);
1347: else if (! _stricmp(colour, "mediumorchid")) return RGB(186,85,211);
1348: else if (! _stricmp(colour, "mediumpurple")) return RGB(147,112,219);
1349: else if (! _stricmp(colour, "mediumseagreen")) return RGB(60,179,113);
1350: else if (! _stricmp(colour, "mediumslateblue")) return RGB(123,104,238);
1351: else if (! _stricmp(colour, "mediumspringgreen")) return RGB(0,250,154);
1352: else if (! _stricmp(colour, "mediumturquoise")) return RGB(72,209,204);
1353: else if (! _stricmp(colour, "mediumvioletred")) return RGB(199,21,133);
1354: else if (! _stricmp(colour, "midnightblue")) return RGB(25,25,112);
1355: else if (! _stricmp(colour, "mintcream")) return RGB(245,255,250);
1356: else if (! _stricmp(colour, "mistyrose")) return RGB(255,228,225);
1357: else if (! _stricmp(colour, "moccasin")) return RGB(255,228,181);
1358: /*
1359: else if (! _stricmp(colour, "magenta1")) return RGB(255,0,255);
1360: else if (! _stricmp(colour, "magenta2")) return RGB(238,0,238);
1361: else if (! _stricmp(colour, "magenta3")) return RGB(205,0,205);
1362: else if (! _stricmp(colour, "magenta4")) return RGB(139,0,139);
1363: else if (! _stricmp(colour, "maroon1")) return RGB(255,52,179);
1364: else if (! _stricmp(colour, "maroon2")) return RGB(238,48,167);
1365: else if (! _stricmp(colour, "maroon3")) return RGB(205,41,144);
1366: else if (! _stricmp(colour, "maroon4")) return RGB(139,28,98);
1367: else if (! _stricmp(colour, "mediumorchid1")) return RGB(224,102,255);
1368: else if (! _stricmp(colour, "mediumorchid2")) return RGB(209,95,238);
1369: else if (! _stricmp(colour, "mediumorchid3")) return RGB(180,82,205);
1370: else if (! _stricmp(colour, "mediumorchid4")) return RGB(122,55,139);
1371: else if (! _stricmp(colour, "mediumpurple1")) return RGB(171,130,255);
1372: else if (! _stricmp(colour, "mediumpurple2")) return RGB(159,121,238);
1373: else if (! _stricmp(colour, "mediumpurple3")) return RGB(137,104,205);
1374: else if (! _stricmp(colour, "mediumpurple4")) return RGB(93,71,139);
1375: else if (! _stricmp(colour, "mistyrose1")) return RGB(255,228,225);
1376: else if (! _stricmp(colour, "mistyrose2")) return RGB(238,213,210);
1377: else if (! _stricmp(colour, "mistyrose3")) return RGB(205,183,181);
1378: else if (! _stricmp(colour, "mistyrose4")) return RGB(139,125,123);
1379: */
1380: }
1381: case 'n': //====================
1382: {
1383: if (! _stricmp(colour, "navajowhite")) return RGB(255,222,173);
1384: else if (! _stricmp(colour, "navy")) return RGB(0,0,128);
1385: else if (! _stricmp(colour, "navyblue")) return RGB(0,0,128);
1386: /*
1387: else if (! _stricmp(colour, "navajowhite1")) return RGB(255,222,173);
1388: else if (! _stricmp(colour, "navajowhite2")) return RGB(238,207,161);
1389: else if (! _stricmp(colour, "navajowhite3")) return RGB(205,179,139);
1390: else if (! _stricmp(colour, "navajowhite4")) return RGB(139,121,94);
1391: */
1392: }
1393: case 'o': //====================
1394: {
1395: if (! _stricmp(colour, "oldlace")) return RGB(253,245,230);
1396: else if (! _stricmp(colour, "olivedrab")) return RGB(107,142,35);
1397: else if (! _stricmp(colour, "orange")) return RGB(255,165,0);
1398: else if (! _stricmp(colour, "orangered")) return RGB(255,69,0);
1399: else if (! _stricmp(colour, "orchid")) return RGB(218,112,214);
1400: /*
1401: else if (! _stricmp(colour, "olivedrab1")) return RGB(192,255,62);
1402: else if (! _stricmp(colour, "olivedrab2")) return RGB(179,238,58);
1403: else if (! _stricmp(colour, "olivedrab3")) return RGB(154,205,50);
1404: else if (! _stricmp(colour, "olivedrab4")) return RGB(105,139,34);
1405: else if (! _stricmp(colour, "orange1")) return RGB(255,165,0);
1406: else if (! _stricmp(colour, "orange2")) return RGB(238,154,0);
1407: else if (! _stricmp(colour, "orange3")) return RGB(205,133,0);
1408: else if (! _stricmp(colour, "orange4")) return RGB(139,90,0);
1409: else if (! _stricmp(colour, "orangered1")) return RGB(255,69,0);
1410: else if (! _stricmp(colour, "orangered2")) return RGB(238,64,0);
1411: else if (! _stricmp(colour, "orangered3")) return RGB(205,55,0);
1412: else if (! _stricmp(colour, "orangered4")) return RGB(139,37,0);
1413: else if (! _stricmp(colour, "orchid1")) return RGB(255,131,250);
1414: else if (! _stricmp(colour, "orchid2")) return RGB(238,122,233);
1415: else if (! _stricmp(colour, "orchid3")) return RGB(205,105,201);
1416: else if (! _stricmp(colour, "orchid4")) return RGB(139,71,137);
1417: */
1418: }
1419: case 'p': //====================
1420: {
1421: if (! _stricmp(colour, "palegoldenrod")) return RGB(238,232,170);
1422: else if (! _stricmp(colour, "palegreen")) return RGB(152,251,152);
1423: else if (! _stricmp(colour, "paleturquoise")) return RGB(175,238,238);
1424: else if (! _stricmp(colour, "palevioletred")) return RGB(219,112,147);
1425: else if (! _stricmp(colour, "papayawhip")) return RGB(255,239,213);
1426: else if (! _stricmp(colour, "peachpuff")) return RGB(255,218,185);
1427: else if (! _stricmp(colour, "peru")) return RGB(205,133,63);
1428: else if (! _stricmp(colour, "pink")) return RGB(255,192,203);
1429: else if (! _stricmp(colour, "plum")) return RGB(221,160,221);
1430: else if (! _stricmp(colour, "powderblue")) return RGB(176,224,230);
1431: else if (! _stricmp(colour, "purple")) return RGB(160,32,240);
1432: /*
1433: else if (! _stricmp(colour, "palegreen1")) return RGB(154,255,154);
1434: else if (! _stricmp(colour, "palegreen2")) return RGB(144,238,144);
1435: else if (! _stricmp(colour, "palegreen3")) return RGB(124,205,124);
1436: else if (! _stricmp(colour, "palegreen4")) return RGB(84,139,84);
1437: else if (! _stricmp(colour, "palevioletred1")) return RGB(255,130,171);
1438: else if (! _stricmp(colour, "palevioletred2")) return RGB(238,121,159);
1439: else if (! _stricmp(colour, "palevioletred3")) return RGB(205,104,137);
1440: else if (! _stricmp(colour, "palevioletred4")) return RGB(139,71,93);
1441: else if (! _stricmp(colour, "paleturquoise1")) return RGB(187,255,255);
1442: else if (! _stricmp(colour, "paleturquoise2")) return RGB(174,238,238);
1443: else if (! _stricmp(colour, "paleturquoise3")) return RGB(150,205,205);
1444: else if (! _stricmp(colour, "paleturquoise4")) return RGB(102,139,139);
1445: else if (! _stricmp(colour, "peachpuff1")) return RGB(255,218,185);
1446: else if (! _stricmp(colour, "peachpuff2")) return RGB(238,203,173);
1447: else if (! _stricmp(colour, "peachpuff3")) return RGB(205,175,149);
1448: else if (! _stricmp(colour, "peachpuff4")) return RGB(139,119,101);
1449: else if (! _stricmp(colour, "pink1")) return RGB(255,181,197);
1450: else if (! _stricmp(colour, "pink2")) return RGB(238,169,184);
1451: else if (! _stricmp(colour, "pink3")) return RGB(205,145,158);
1452: else if (! _stricmp(colour, "pink4")) return RGB(139,99,108);
1453: else if (! _stricmp(colour, "plum1")) return RGB(255,187,255);
1454: else if (! _stricmp(colour, "plum2")) return RGB(238,174,238);
1455: else if (! _stricmp(colour, "plum3")) return RGB(205,150,205);
1456: else if (! _stricmp(colour, "plum4")) return RGB(139,102,139);
1457: else if (! _stricmp(colour, "purple1")) return RGB(155,48,255);
1458: else if (! _stricmp(colour, "purple2")) return RGB(145,44,238);
1459: else if (! _stricmp(colour, "purple3")) return RGB(125,38,205);
1460: else if (! _stricmp(colour, "purple4")) return RGB(85,26,139);
1461: */
1462: }
1463: case 'r': //====================
1464: {
1465: if (! _stricmp(colour, "red")) return RGB(255,0,0);
1466: else if (! _stricmp(colour, "rosybrown")) return RGB(188,143,143);
1467: else if (! _stricmp(colour, "royalblue")) return RGB(65,105,225);
1468: /*
1469: else if (! _stricmp(colour, "red1")) return RGB(255,0,0);
1470: else if (! _stricmp(colour, "red2")) return RGB(238,0,0);
1471: else if (! _stricmp(colour, "red3")) return RGB(205,0,0);
1472: else if (! _stricmp(colour, "red4")) return RGB(139,0,0);
1473: else if (! _stricmp(colour, "rosybrown1")) return RGB(255,193,193);
1474: else if (! _stricmp(colour, "rosybrown2")) return RGB(238,180,180);
1475: else if (! _stricmp(colour, "rosybrown3")) return RGB(205,155,155);
1476: else if (! _stricmp(colour, "rosybrown4")) return RGB(139,105,105);
1477: else if (! _stricmp(colour, "royalblue1")) return RGB(72,118,255);
1478: else if (! _stricmp(colour, "royalblue2")) return RGB(67,110,238);
1479: else if (! _stricmp(colour, "royalblue3")) return RGB(58,95,205);
1480: else if (! _stricmp(colour, "royalblue4")) return RGB(39,64,139);
1481: */
1482: }
1483: case 's': //====================
1484: {
1485: if (! _stricmp(colour, "saddlebrown")) return RGB(139,69,19);
1486: else if (! _stricmp(colour, "salmon")) return RGB(250,128,114);
1487: else if (! _stricmp(colour, "sandybrown")) return RGB(244,164,96);
1488: else if (! _stricmp(colour, "seagreen")) return RGB(46,139,87);
1489: else if (! _stricmp(colour, "seashell")) return RGB(255,245,238);
1490: else if (! _stricmp(colour, "sienna")) return RGB(160,82,45);
1491: else if (! _stricmp(colour, "skyblue")) return RGB(135,206,235);
1492: else if (! _stricmp(colour, "slateblue")) return RGB(106,90,205);
1493: else if (! _stricmp(colour, "slategray")) return RGB(112,128,144);
1494: else if (! _stricmp(colour, "slategrey")) return RGB(112,128,144);
1495: else if (! _stricmp(colour, "springgreen")) return RGB(0,255,127);
1496: else if (! _stricmp(colour, "steelblue")) return RGB(70,130,180);
1497: /*
1498: else if (! _stricmp(colour, "salmon1")) return RGB(255,140,105);
1499: else if (! _stricmp(colour, "salmon2")) return RGB(238,130,98);
1500: else if (! _stricmp(colour, "salmon3")) return RGB(205,112,84);
1501: else if (! _stricmp(colour, "salmon4")) return RGB(139,76,57);
1502: else if (! _stricmp(colour, "seagreen1")) return RGB(84,255,159);
1503: else if (! _stricmp(colour, "seagreen2")) return RGB(78,238,148);
1504: else if (! _stricmp(colour, "seagreen3")) return RGB(67,205,128);
1505: else if (! _stricmp(colour, "seagreen4")) return RGB(46,139,87);
1506: else if (! _stricmp(colour, "seashell1")) return RGB(255,245,238);
1507: else if (! _stricmp(colour, "seashell2")) return RGB(238,229,222);
1508: else if (! _stricmp(colour, "seashell3")) return RGB(205,197,191);
1509: else if (! _stricmp(colour, "seashell4")) return RGB(139,134,130);
1510: else if (! _stricmp(colour, "sienna1")) return RGB(255,130,71);
1511: else if (! _stricmp(colour, "sienna2")) return RGB(238,121,66);
1512: else if (! _stricmp(colour, "sienna3")) return RGB(205,104,57);
1513: else if (! _stricmp(colour, "sienna4")) return RGB(139,71,38);
1514: else if (! _stricmp(colour, "skyblue1")) return RGB(135,206,255);
1515: else if (! _stricmp(colour, "skyblue2")) return RGB(126,192,238);
1516: else if (! _stricmp(colour, "skyblue3")) return RGB(108,166,205);
1517: else if (! _stricmp(colour, "skyblue4")) return RGB(74,112,139);
1518: else if (! _stricmp(colour, "slateblue1")) return RGB(131,111,255);
1519: else if (! _stricmp(colour, "slateblue2")) return RGB(122,103,238);
1520: else if (! _stricmp(colour, "slateblue3")) return RGB(105,89,205);
1521: else if (! _stricmp(colour, "slateblue4")) return RGB(71,60,139);
1522: else if (! _stricmp(colour, "slategray1")) return RGB(198,226,255);
1523: else if (! _stricmp(colour, "slategray2")) return RGB(185,211,238);
1524: else if (! _stricmp(colour, "slategray3")) return RGB(159,182,205);
1525: else if (! _stricmp(colour, "slategray4")) return RGB(108,123,139);
1526: else if (! _stricmp(colour, "snow1")) return RGB(255,250,250);
1527: else if (! _stricmp(colour, "snow2")) return RGB(238,233,233);
1528: else if (! _stricmp(colour, "snow3")) return RGB(205,201,201);
1529: else if (! _stricmp(colour, "snow4")) return RGB(139,137,137);
1530: else if (! _stricmp(colour, "springgreen1")) return RGB(0,255,127);
1531: else if (! _stricmp(colour, "springgreen2")) return RGB(0,238,118);
1532: else if (! _stricmp(colour, "springgreen3")) return RGB(0,205,102);
1533: else if (! _stricmp(colour, "springgreen4")) return RGB(0,139,69);
1534: else if (! _stricmp(colour, "steelblue1")) return RGB(99,184,255);
1535: else if (! _stricmp(colour, "steelblue2")) return RGB(92,172,238);
1536: else if (! _stricmp(colour, "steelblue3")) return RGB(79,148,205);
1537: else if (! _stricmp(colour, "steelblue4")) return RGB(54,100,139);
1538: */
1539: }
1540: case 't': //====================
1541: {
1542: if (! _stricmp(colour, "tan")) return RGB(210,180,140);
1543: else if (! _stricmp(colour, "thistle")) return RGB(216,191,216);
1544: else if (! _stricmp(colour, "tomato")) return RGB(255,99,71);
1545: else if (! _stricmp(colour, "turquoise")) return RGB(64,224,208);
1546: /*
1547: else if (! _stricmp(colour, "tan1")) return RGB(255,165,79);
1548: else if (! _stricmp(colour, "tan2")) return RGB(238,154,73);
1549: else if (! _stricmp(colour, "tan3")) return RGB(205,133,63);
1550: else if (! _stricmp(colour, "tan4")) return RGB(139,90,43);
1551: else if (! _stricmp(colour, "thistle1")) return RGB(255,225,255);
1552: else if (! _stricmp(colour, "thistle2")) return RGB(238,210,238);
1553: else if (! _stricmp(colour, "thistle3")) return RGB(205,181,205);
1554: else if (! _stricmp(colour, "thistle4")) return RGB(139,123,139);
1555: else if (! _stricmp(colour, "tomato1")) return RGB(255,99,71);
1556: else if (! _stricmp(colour, "tomato2")) return RGB(238,92,66);
1557: else if (! _stricmp(colour, "tomato3")) return RGB(205,79,57);
1558: else if (! _stricmp(colour, "tomato4")) return RGB(139,54,38);
1559: else if (! _stricmp(colour, "turquoise1")) return RGB(0,245,255);
1560: else if (! _stricmp(colour, "turquoise2")) return RGB(0,229,238);
1561: else if (! _stricmp(colour, "turquoise3")) return RGB(0,197,205);
1562: else if (! _stricmp(colour, "turquoise4")) return RGB(0,134,139);
1563: */
1564: }
1565: case 'v': //====================
1566: {
1567: if (! _stricmp(colour, "violet")) return RGB(238,130,238);
1568: else if (! _stricmp(colour, "violetred")) return RGB(208,32,144);
1569: /*
1570: else if (! _stricmp(colour, "violetred1")) return RGB(255,62,150);
1571: else if (! _stricmp(colour, "violetred2")) return RGB(238,58,140);
1572: else if (! _stricmp(colour, "violetred3")) return RGB(205,50,120);
1573: else if (! _stricmp(colour, "violetred4")) return RGB(139,34,82);
1574: */
1575: }
1576: case 'w': //====================
1577: {
1578: if (! _stricmp(colour, "wheat")) return RGB(245,222,179);
1579: else if (! _stricmp(colour, "white")) return RGB(255,255,255);
1580: else if (! _stricmp(colour, "whitesmoke")) return RGB(245,245,245);
1581: /*
1582: else if (! _stricmp(colour, "wheat1")) return RGB(255,231,186);
1583: else if (! _stricmp(colour, "wheat2")) return RGB(238,216,174);
1584: else if (! _stricmp(colour, "wheat3")) return RGB(205,186,150);
1585: else if (! _stricmp(colour, "wheat4")) return RGB(139,126,102);
1586: */
1587: }
1588: case 'y': //====================
1589: {
1590: if (! _stricmp(colour, "yellow")) return RGB(255,255,0);
1591: else if (! _stricmp(colour, "yellowgreen")) return RGB(154,205,50);
1592: /*
1593: else if (! _stricmp(colour, "yellow1")) return RGB(255,255,0);
1594: else if (! _stricmp(colour, "yellow2")) return RGB(238,238,0);
1595: else if (! _stricmp(colour, "yellow3")) return RGB(205,205,0);
1596: else if (! _stricmp(colour, "yellow4")) return RGB(139,139,0);
1597: */
1598: }
1599:
1600: //====================
1601:
1602: default:
1603: return 0x000000;
1604: }
1605: }
1606:
1607: //===========================================================================
1608: // Function: MBoxErrorFile
1609: // Purpose: Gives a message box proclaming missing file
1610: // In: LPCSTR = missing file
1611: // Out: int = return value of messagebox
1612: //===========================================================================
1613:
1614: int MBoxErrorFile(LPCSTR szFile)
1615: {
1616: sprintf_s(tempBuf, sizeofArray(tempBuf), "Error: Unable to open file \"%s\". Please check location and try again.", szFile);
1617: Log("MBoxErrorFile Called", szFile);
1618:
1619: return MessageBox(GetBBWnd(), tempBuf, "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
1620: }
1621:
1622: //===========================================================================
1623: // Function: MBoxErrorValue
1624: // Purpose: Gives a message box proclaming a given value
1625: // In: LPCSTR = value
1626: // Out: int = return value of messagebox
1627: //===========================================================================
1628:
1629: int MBoxErrorValue(LPCSTR szValue)
1630: {
1631: sprintf_s(tempBuf, sizeofArray(tempBuf), "Error: %s", szValue);
1632: Log("MBoxErrorValue Called", szValue);
1633:
1634: return MessageBox(GetBBWnd(), tempBuf, "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
1635: }
1636:
1637: //===========================================================================
1638: // Function: BBExecute
1639: // Purpose: A safe execute routine
1640: // In: HWND = owner
1641: // In: LPCSTR = operation (eg. "open")
1642: // In: LPCSTR = command to run
1643: // In: LPCSTR = arguments
1644: // In: LPCSTR = directory to run from
1645: // In: int = show status
1646: // In: bool = suppress error messages
1647: // Out: HINSTANCE = instance of file running
1648: //===========================================================================
1649:
1650: HINSTANCE BBExecute(HWND Owner, LPCSTR szOperation, LPCSTR szCommand, LPCSTR szArgs, LPCSTR szDirectory, int nShowCmd, bool noErrorMsgs)
1651: {
1652: if (!strlen(szCommand)) return HINSTANCE(32);
1653:
1654: //====================
1655:
1656: HINSTANCE retValue;
1657: PVOID oldRedirectionValue;
1658:
1659: //====================
1660:
1661: if (pSettings->runningUnderWOW64)
1662: {
1663: LPFN_WOW64_DISABLE_REDIRECTION BBWow64DisableRedirection = (LPFN_WOW64_DISABLE_REDIRECTION)GetProcAddress(GetModuleHandle("kernel32"),"Wow64DisableWow64FsRedirection");
1664: BBWow64DisableRedirection(&oldRedirectionValue);
1665: }
1666:
1667: //====================
1668:
1669: DWORD type = GetFileAttributes(szCommand);
1670:
1671: if (type & FILE_ATTRIBUTE_DIRECTORY && type != 0xFFFFFFFF)
1672: {
1673: retValue = ShellExecute(Owner, szOperation, szCommand, szArgs, NULL, nShowCmd ? nShowCmd : SW_SHOWNORMAL);
1674: }
1675: else
1676: {
1677: SHELLEXECUTEINFO si;
1678: ZeroMemory(&si, sizeof(si));
1679: si.cbSize = sizeof(SHELLEXECUTEINFO);
1680: si.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI;
1681: si.hwnd = Owner;
1682: si.lpVerb = szOperation;
1683:
1684: if ((strlen(szCommand) >= 4) && (!_stricmp(&szCommand[strlen(szCommand)-4], ".lnk")))
1685: {
1686: // Let Explorer execute .lnk shortcuts to (hopefully?)
1687: // avoid some potential WoW64 redirection related issues...
1688: si.lpFile = "explorer";
1689: si.lpParameters = szCommand;
1690: si.lpDirectory = NULL;
1691: }
1692: else
1693: {
1694: // ...otherwise use ShellExecuteEx as usual...
1695: si.lpFile = szCommand;
1696: si.lpParameters = szArgs;
1697: si.lpDirectory = szDirectory;
1698: }
1699: si.nShow = nShowCmd ? nShowCmd : SW_SHOWNORMAL;
1700:
1701: BOOL result = ShellExecuteEx(&si);
1702:
1703: if (((result == FALSE) || ((int)si.hInstApp <= 32)) && !noErrorMsgs)
1704: {
1705: DWORD error = GetLastError();
1706:
1707: char msg[MAX_LINE_LENGTH];
1708: _snprintf_s(msg, sizeofArray(msg), _TRUNCATE, "%s %s (%s)", szCommand, szArgs, szDirectory);
1709: Log("BBExecute failed", msg);
1710:
1711: strcpy_s(msg, sizeofArray(msg), "ERROR: Could not execute ");
1712: strncat_s(msg, sizeofArray(msg), szCommand, 128);
1713: if (strlen(szCommand) >= 128) strcat_s(msg, sizeofArray(msg), "..."); // ...truncating long paths for the console error message...
1714:
1715: switch (error)
1716: {
1717: case ERROR_PATH_NOT_FOUND: { strcat_s(msg, sizeofArray(msg), " -> Path not found!"); break; }
1718: case ERROR_DDE_FAIL: { strcat_s(msg, sizeofArray(msg), " -> DDE transaction failed!"); break; }
1719: case ERROR_NO_ASSOCIATION: { strcat_s(msg, sizeofArray(msg), " -> No application associated with extension!"); break; }
1720: case ERROR_ACCESS_DENIED: { strcat_s(msg, sizeofArray(msg), " -> Access denied!"); break; }
1721: case ERROR_DLL_NOT_FOUND: { strcat_s(msg, sizeofArray(msg), " -> DLL not found!"); break; }
1722: case ERROR_CANCELLED: { strcat_s(msg, sizeofArray(msg), " -> Cancelled!"); break; }
1723: case ERROR_NOT_ENOUGH_MEMORY: { strcat_s(msg, sizeofArray(msg), " -> Not enough memory!"); break; }
1724: case ERROR_SHARING_VIOLATION: { strcat_s(msg, sizeofArray(msg), " -> Sharing violation!"); break; }
1725: default: { strcat_s(msg, sizeofArray(msg), " -> File not found!"); break; } // ERROR_FILE_NOT_FOUND
1726: }
1727:
1728: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_ERROR_MESSAGE, (LPARAM)msg);
1729: /*
1730: if (pSettings->debugLogging)
1731: {
1732: sprintf_s(msg, sizeofArray(msg), "DEBUG -> Command: %s / Arguments: %s / Directory: %s", szCommand, szArgs, szDirectory);
1733: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
1734: }
1735: */
1736: /*
1737: strcpy_s(msg, sizeofArray(msg), "Could not execute...\n\nCommand:\n");
1738:
1739: if (szCommand != NULL) strcat_s(msg, sizeofArray(msg), szCommand);
1740: strcat_s(msg, sizeofArray(msg), " \n\nArguments:\n");
1741: if (szArgs != NULL) strcat_s(msg, sizeofArray(msg), szArgs);
1742: strcat_s(msg, sizeofArray(msg), " \n\nWorking directory:\n");
1743: if (szDirectory != NULL) strcat_s(msg, sizeofArray(msg), szDirectory);
1744: strcat_s(msg, sizeofArray(msg), " ");
1745:
1746: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
1747: */
1748: }
1749:
1750: retValue = si.hInstApp;
1751: }
1752:
1753: //====================
1754:
1755: if (pSettings->runningUnderWOW64)
1756: {
1757: LPFN_WOW64_REVERT_REDIRECTION BBWow64RevertRedirection = (LPFN_WOW64_REVERT_REDIRECTION)GetProcAddress(GetModuleHandle("kernel32"),"Wow64RevertWow64FsRedirection");
1758: BBWow64RevertRedirection(&oldRedirectionValue);
1759: }
1760:
1761: return retValue;
1762: }
1763:
1764: //===========================================================================
1765: // Function: BBSmartExecute
1766: // Purpose: ...
1767: //===========================================================================
1768:
1769: void BBSmartExecute(LPSTR inputString)
1770: {
1771: if (!strlen(inputString)) return;
1772:
1773: //====================
1774:
1775: if (inputString[0] == '@') // Broadcast message (bro@m)
1776: {
1777: // Note: We need to use SendMessage() here for any "parent" @Script scripts to be executing sequentially!
1778: // (i.e. if we had used PostMessage() here any @Script "child" bro@ms would be more like executing in parallel...)
1779: SendMessage(GetBBWnd(), BB_BROADCAST, 0, (LPARAM)inputString);
1780: }
1781:
1782: //====================
1783:
1784: else if (!_strnicmp(inputString, "Pause", 5)) // @Script Pause <milliseconds> command
1785: {
1786: Sleep(atoi(&inputString[6]));
1787: }
1788:
1789: //====================
1790:
1791: else if ((!_strnicmp(inputString, "? ", 2)) && (strlen(inputString) > 2))
1792: {
1793: // Open the default browser to perform a web search using DuckDuckGo...
1794: char searchString[MAX_LINE_LENGTH];
1795: sprintf_s(searchString, sizeofArray(searchString), "https://duckduckgo.com/?q=\"%s\"", &inputString[2]);
1796: BBSmartExecute(searchString);
1797: }
1798:
1799: else if ((!_strnicmp(inputString, "http", 4)) && pPluginManager->IsPluginLoaded("xWebViewer"))
1800: // else if ((!_strnicmp(inputString, "http://xoblite.net/", 19)) && pPluginManager->IsPluginLoaded("xWebViewer"))
1801: {
1802: // Open the URL in the xWebViewer plugin... (nb. if the plugin is *not* loaded, the URL will open in the default browser instead)
1803: char broam[MAX_LINE_LENGTH];
1804: sprintf_s(broam, sizeofArray(broam), "@xWebViewer URL %s", inputString);
1805: BBSmartExecute(broam);
1806: }
1807:
1808: //====================
1809:
1810: else // Regular command - extract working directory, arguments etc from input string
1811: {
1812: if (strchr(inputString, '$')) ReplaceShellFolders(inputString);
1813: if (strchr(inputString, '%')) ReplaceEnvVars(inputString);
1814:
1815: char command[MAX_LINE_LENGTH], arguments[MAX_LINE_LENGTH], workingdir[MAX_LINE_LENGTH];
1816: LPSTR tokens[1];
1817: tokens[0] = command;
1818: command[0] = arguments[0] = workingdir[0] = '\0';
1819: BBTokenize (inputString, tokens, 1, arguments);
1820:
1821: if (command[1] == ':')
1822: {
1823: strcpy_s(workingdir, sizeofArray(workingdir), command);
1824: GetParentFolder(workingdir);
1825: }
1826:
1827: BBExecute(GetDesktopWindow(), NULL, command, arguments, workingdir, SW_SHOWNORMAL, false);
1828:
1829: // PlaySoundFX(SFX_MENU_CLICK);
1830: }
1831: }
1832:
1833: //===========================================================================
1834: // Function: IsAppWindow
1835: // Purpose: Checks a given hwnd to see if it's an application or not...
1836: //===========================================================================
1837:
1838: bool IsAppWindow(HWND hWnd)
1839: {
1840: if (!(GetWindowLong(hWnd, GWL_STYLE) & WS_SYSMENU))
1841: {
1842: char windowClass[MAX_LINE_LENGTH];
1843: GetClassName(hWnd, windowClass, sizeof(windowClass));
1844: if (!_strnicmp(windowClass, "BBAppPlugin", 11)) return true; // Allow specific "application-like" plugins to show up on the taskbar...
1845:
1846: char windowText[MAX_LINE_LENGTH];
1847: GetWindowText(hWnd, windowText, sizeof(windowText));
1848:
1849: // Below: Workarounds for various application not having the WS_SYSMENU flag set...
1850: // (nb. it remains to be seen if other such apps need to be added to this list too)
1851:
1852: if (!_stricmp(windowClass, "MozillaWindowClass"))
1853: {
1854: // ##### Some newer Mozilla Firefox builds (at least version >= 135.0 as of this writing) #####
1855: return true;
1856: }
1857: else if (!_stricmp(windowClass, "Chrome_WidgetWin_1"))
1858: {
1859: // ##### Visual Studio Code, Microsoft Teams and Termius main window (all window class "Chrome_WidgetWin_1") #####
1860: if (IsInString(windowText, "Visual Studio Code") || IsInString(windowText, "Microsoft Teams")) return true;
1861: else if (IsInString(windowText, "Termius -") && _stricmp(windowText, "Termius - Settings")) return true; // ...but not the Termius settings child window
1862:
1863: if (pSettings->debugLogging)
1864: {
1865: char msg[MAX_LINE_LENGTH];
1866: if (hWnd && (strnlen_s(windowText, sizeofArray(windowText)) > 0)) sprintf_s(msg, sizeofArray(msg), "DEBUG -> BBApi::IsAppWindow (Chrome_WidgetWin_1 specific checks) -> WS_SYSMENU check failed! -> %s", windowText);
1867: else strcpy_s(msg, sizeofArray(msg), "DEBUG -> BBApi::IsAppWindow (Chrome_WidgetWin_1 specific checks) -> No HWND!");
1868: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_WARNING_MESSAGE, (LPARAM)msg);
1869: Log(msg, "");
1870: }
1871:
1872: return false;
1873: }
1874: else
1875: {
1876: // ##### Any other applications not having the WS_SYSMENU flag set #####
1877: /*
1878: if (pSettings->debugLogging)
1879: {
1880: char msg[MAX_LINE_LENGTH];
1881: if (hWnd)
1882: {
1883: if (strnlen_s(windowText, sizeofArray(windowText)) > 0) sprintf_s(msg, sizeofArray(msg), "DEBUG -> BBApi::IsAppWindow (non application specific checks) -> WS_SYSMENU check failed! -> %s %s", windowClass, windowText);
1884: // else sprintf_s(msg, sizeofArray(msg), "DEBUG -> BBApi::IsAppWindow (non application specific checks) -> WS_SYSMENU check failed! -> %s <None>", windowClass); // Not really of any interest?
1885: }
1886: else strcpy_s(msg, sizeofArray(msg), "DEBUG -> BBApi::IsAppWindow (non application specific checks) -> No HWND!");
1887: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_WARNING_MESSAGE, (LPARAM)msg);
1888: Log(msg, "");
1889: }
1890: */
1891: return false;
1892: }
1893: }
1894:
1895: //====================
1896:
1897: // if (!(GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE)) return false;
1898: // if (GetWindowLong(hWnd, GWL_STYLE) & WS_DISABLED) return false;
1899:
1900: char windowClass[MAX_LINE_LENGTH];
1901: GetClassName(hWnd, windowClass, sizeof(windowClass));
1902: if (strnlen_s(windowClass, sizeofArray(windowClass)) == 0) return false;
1903: if (!_stricmp(windowClass, "AcrobatOffscreenDocumentWnd")) return false; // Check for Adobe Acrobat 7.0 offscreen windows...
1904:
1905: char windowText[MAX_LINE_LENGTH];
1906: GetWindowText(hWnd, windowText, sizeof(windowText));
1907: if (strnlen_s(windowText, sizeofArray(windowText)) == 0)
1908: {
1909: /*
1910: if (pSettings->debugLogging)
1911: {
1912: char msg[MAX_LINE_LENGTH];
1913: sprintf_s(msg, sizeofArray(msg), "DEBUG -> BBApi::IsAppWindow -> GetWindowText failed! -> %s", windowClass);
1914: // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
1915: Log(msg, "");
1916: }
1917: */
1918: return false;
1919: }
1920:
1921: // if (IsInString(windowText, " Powerpoint - [")) return false; // Check for Microsoft Powerpoint non-document windows... (-> "Microsoft Powerpoint - [" or "Microsoft Office PowerPoint - [" )
1922:
1923: // The Windows 10 Cortana window is seemingly odd, non-cloaking but also non-closeable etc, so shouldn't be shown on the taskbar...
1924: if (!_stricmp(windowText, "Cortana")) return false;
1925:
1926: //====================
1927:
1928: if (IsWindowVisible(hWnd))
1929: {
1930: if (!(GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
1931: {
1932: if (!GetParent(hWnd))
1933: {
1934: HWND hwndOwner = GetWindow(hWnd, GW_OWNER);
1935: if (!hwndOwner ||
1936: ((GetWindowLong(hwndOwner, GWL_STYLE) & (WS_VISIBLE | WS_CLIPCHILDREN)) != (WS_VISIBLE | WS_CLIPCHILDREN)) ||
1937: GetWindowLong(hwndOwner, GWL_EXSTYLE) & WS_EX_TOOLWINDOW )
1938: {
1939: return true;
1940: }
1941: // else if (pSettings->debugLogging && IsInString(windowClass, "Chrome_WidgetWin")) Log("...Chrome_WidgetWin -> IsWindowVisible GetWindow etc checks failed!", "");
1942: }
1943: // else if (pSettings->debugLogging && IsInString(windowClass, "Chrome_WidgetWin")) Log("...Chrome_WidgetWin -> IsWindowVisible GetParent check failed!", "");
1944: }
1945: // else if (pSettings->debugLogging && IsInString(windowClass, "Chrome_WidgetWin")) Log("...Chrome_WidgetWin -> IsWindowVisible GetWindowLong check failed!", "");
1946: }
1947: /*
1948: else if (pSettings->debugLogging)
1949: {
1950: if (IsInString(windowClass, "Chrome_WidgetWin"))
1951: {
1952: char msg[MAX_LINE_LENGTH];
1953: if (!strnlen_s(windowText, sizeofArray(windowText))) strcpy_s(windowText, sizeofArray(windowText), "NULL");
1954: sprintf_s(msg, sizeofArray(msg), "DEBUG -> BBApi::IsAppWindow -> IsWindowVisible etc checks failed! -> %s | %s", windowText, windowClass);
1955: // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
1956: Log(msg, "");
1957: }
1958: }
1959: */
1960: return false;
1961: }
1962:
1963: //===========================================================================
1964: // Function: SnapWindowToEdge
1965: // Purpose:Snaps a given windowpos at a specified distance
1966: // In: WINDOWPOS* = WINDOWPOS recieved from WM_WINDOWPOSCHANGING
1967: // In: int = distance to snap to
1968: // In: bool = use screensize of workspace
1969: // Out: void = none
1970: //===========================================================================
1971:
1972: void SnapWindowToEdge(WINDOWPOS* pwPos, int nDist, bool bUseScreenSize)
1973: {
1974: RECT workArea;
1975: ZeroMemory(&workArea, sizeof(workArea));
1976: int nTemp;
1977:
1978: //====================
1979:
1980: if (bUseScreenSize)
1981: {
1982: workArea.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
1983: workArea.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);
1984: }
1985: else
1986: {
1987: SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1988: }
1989:
1990: //====================
1991:
1992: // Left edge
1993: nTemp = pwPos->x - workArea.left;
1994: if (nTemp < nDist && nTemp > -nDist)
1995: pwPos->x = workArea.left;
1996:
1997: // Top edge
1998: nTemp = pwPos->y - workArea.top;
1999: if (nTemp < nDist && nTemp > -nDist)
2000: pwPos->y = workArea.top;
2001:
2002: // Right edge
2003: nTemp = workArea.right - (pwPos->x + pwPos->cx);
2004: if (nTemp < nDist && nTemp > -nDist)
2005: pwPos->x = workArea.right - pwPos->cx;
2006:
2007: // Bottom edge
2008: nTemp = workArea.bottom - (pwPos->y + pwPos->cy);
2009: if (nTemp < nDist && nTemp > -nDist)
2010: pwPos->y = workArea.bottom - pwPos->cy;
2011: }
2012:
2013: //===========================================================================
2014: // Function: GetPositionEvolved
2015: // Purpose:
2016: //===========================================================================
2017:
2018: void GetPositionEvolved(LPSTR placement, SIZE size, POINT* pt)
2019: {
2020: Placement tempPlacement;
2021: tempPlacement.width = size.cx;
2022: tempPlacement.height = size.cy;
2023:
2024: pSettings->ParsePlacement(placement, &tempPlacement);
2025: pSettings->PositionFromPlacement(&tempPlacement);
2026:
2027: pt->x = tempPlacement.x;
2028: pt->y = tempPlacement.y;
2029: }
2030:
2031: //===========================================================================
2032: // Function: FindStyleElement
2033: // Purpose: Helper function to MakeGradientEvolved/DrawTextEvolved;
2034: // finds the StyleItem* for a given style element string
2035: //===========================================================================
2036:
2037: StyleItem* FindStyleElement(LPSTR styleElement)
2038: {
2039: if (IsInString(styleElement, "toolbar"))
2040: {
2041: if (IsInString(styleElement, "windowLabel")) return pSettings->ToolbarWindowLabel; // toolbar.windowLabel
2042: else if (IsInString(styleElement, "label")) return pSettings->ToolbarLabel; // toolbar.label
2043: else if (IsInString(styleElement, "clock")) return pSettings->ToolbarClock; // toolbar.clock
2044: else if (IsInString(styleElement, "pressed")) return pSettings->ToolbarButtonPressed; // toolbar.button.pressed
2045: else if (IsInString(styleElement, "button")) return pSettings->ToolbarButton; // toolbar.button
2046: else return pSettings->Toolbar; // toolbar (i.e. the background)
2047: }
2048: else if (IsInString(styleElement, "menu"))
2049: {
2050: if (IsInString(styleElement, "title")) return pSettings->MenuTitle; // menu.title
2051: else if (IsInString(styleElement, "hilite")) return pSettings->MenuActive; // menu.hilite (i.e. legacy bb4nix syntax menu.active)
2052: else if (IsInString(styleElement, "active")) return pSettings->MenuActive; // menu.active (i.e. bb4nix 0.70 syntax menu.hilite)
2053: else if (IsInString(styleElement, "grip")) return pSettings->MenuGrip; // menu.grip
2054: else return pSettings->MenuFrame; // menu.frame
2055: }
2056: else if (IsInString(styleElement, "dock")) return pSettings->Dock; // dock
2057: else if (IsInString(styleElement, "slit")) return pSettings->Dock; // + backwards compatibility with old "slit" syntax
2058: else if (IsInString(styleElement, "console")) return pSettings->Console; // console
2059: else if (IsInString(styleElement, "window"))
2060: {
2061: if (IsInString(styleElement, "title"))
2062: {
2063: if (IsInString(styleElement, "unfocus")) return pSettings->WindowTitleUnfocus; // window.title.unfocus
2064: else return pSettings->WindowTitleFocus; // window.title.focus
2065: }
2066: else if (IsInString(styleElement, "label"))
2067: {
2068: if (IsInString(styleElement, "unfocus")) return pSettings->WindowLabelUnfocus; // window.label.unfocus
2069: else return pSettings->WindowLabelFocus; // window.label.focus
2070: }
2071: else if (IsInString(styleElement, "button"))
2072: {
2073: if (IsInString(styleElement, "pressed")) return pSettings->WindowButtonPressed; // window.button.pressed
2074: else if (IsInString(styleElement, "unfocus")) return pSettings->WindowButtonUnfocus; // window.button.unfocus
2075: else return pSettings->WindowButtonFocus; //window.button.focus
2076: }
2077: else if (IsInString(styleElement, "grip"))
2078: {
2079: if (IsInString(styleElement, "unfocus")) return pSettings->WindowGripUnfocus; // window.grip.unfocus
2080: else return pSettings->WindowGripFocus; // window.grip.focus
2081: }
2082: else if (IsInString(styleElement, "handle"))
2083: {
2084: if (IsInString(styleElement, "unfocus")) return pSettings->WindowHandleUnfocus; // window.handle.unfocus
2085: else return pSettings->WindowHandleFocus; // window.handle.focus
2086: }
2087: // else if (IsInString(styleElement, "frame")) return pSettings->WindowFrame; // window.frame
2088: }
2089:
2090: return NULL;
2091: }
2092:
2093: //===========================================================================
2094: // Function: GetMetricsEvolved
2095: // Purpose: Fetches a single metric, or the sum of several metrics
2096: // (this is typically used e.g. to calculate element paddings etc)
2097: //===========================================================================
2098:
2099: int GetMetricsEvolved(LPSTR styleElement, int metricsToInclude)
2100: {
2101: StyleItem* element = FindStyleElement(styleElement);
2102:
2103: if (element != NULL) // -> Supported style element found!
2104: {
2105: int padding = 0;
2106: if (metricsToInclude & METRIC_BORDER) padding += element->borderWidth;
2107: if (metricsToInclude & METRIC_MARGIN) padding += element->marginWidth;
2108: if (metricsToInclude & METRIC_BEVEL)
2109: {
2110: if (element->bevelstyle != BEVEL_FLAT)
2111: {
2112: if (element->bevelposition == BEVEL2) padding += 2;
2113: else padding += 1;
2114: }
2115: }
2116: return padding;
2117: }
2118: else return 0; // -> Unsupported style element...
2119: }
2120:
2121: //===========================================================================
2122: // Functions: MakeGradientSuper/MakeGradientEx/MakeGradient/
2123: // MakeGradientEvolved/MakeStyleGradient
2124: // Purpose: Draws a gradient based on the specified input parameters
2125: //===========================================================================
2126:
2127: RECT gradientRect;
2128:
2129: void MakeGradientSuper(HDC hdc, RECT rect, int type, COLORREF color1, COLORREF color2, COLORREF color3, COLORREF color4, COLORREF color5, COLORREF color6, COLORREF color7, COLORREF color8, bool bInterlaced, int bevelStyle, int bevelPosition, int bevelWidth, COLORREF borderColour, int borderWidth)
2130: {
2131: if (borderWidth > 0)
2132: {
2133: gradientRect.left = rect.left + borderWidth;
2134: gradientRect.top = rect.top + borderWidth;
2135: gradientRect.right = rect.right - borderWidth;
2136: gradientRect.bottom = rect.bottom - borderWidth;
2137:
2138: pBImage->DrawBorder(hdc, rect, borderColour, borderWidth);
2139: pBImage->DrawGradient(hdc, gradientRect, type, color1, color2, color3, color4, color5, color6, color7, color8, bInterlaced, bevelStyle, bevelPosition, bevelWidth);
2140: }
2141: else pBImage->DrawGradient(hdc, rect, type, color1, color2, color3, color4, color5, color6, color7, color8, bInterlaced, bevelStyle, bevelPosition, bevelWidth);
2142: }
2143:
2144: //====================
2145:
2146: void MakeGradientEx(HDC hdc, RECT rect, int type, COLORREF color1, COLORREF color2, COLORREF split1, COLORREF split2, bool bInterlaced, int bevelStyle, int bevelPosition, int bevelWidth, COLORREF borderColour, int borderWidth)
2147: {
2148: // Below: Allow limited "forwards compatibility" by supporting down-parsing of newer, otherwise normally 8-colour gradients,
2149: // to use only the 4 supplied input colours (i.e. at least avoiding partially "black" renders)
2150: int allowedType = type;
2151: if (type == B_SUPERHORIZONTAL || type == B_SUPERVERTICAL) allowedType -= 50; // -> Converted to 4-colour B_SPLITHORIZONTAL and B_SPLITVERTICAL respectively
2152:
2153: MakeGradientSuper(hdc, rect, allowedType, color1, color2, split1, split2, 0, 0, 0, 0, bInterlaced, bevelStyle, bevelPosition, bevelWidth, borderColour, borderWidth);
2154: }
2155:
2156: //====================
2157:
2158: void MakeGradient(HDC hdc, RECT rect, int type, COLORREF color1, COLORREF color2, bool interlaced, int bevelStyle, int bevelPosition, int bevelWidth, COLORREF borderColor, int borderWidth)
2159: {
2160: // Below: Allow limited "forwards compatibility" by supporting down-parsing of newer, otherwise normally 4- or 8-colour gradients,
2161: // to use only the 2 supplied input colours (i.e. at least avoiding partially "black" renders)
2162: int allowedType = type;
2163: if (type == B_SUPERHORIZONTAL || type == B_SUPERVERTICAL) allowedType -= 150; // -> Converted to 2-colour B_HORIZONTAL and B_VERTICAL respectively
2164: else if (type == B_SPLITHORIZONTAL || type == B_SPLITVERTICAL || type == B_SPLITSOLID) allowedType -= 100; // (etc)
2165:
2166: MakeGradientSuper(hdc, rect, allowedType, color1, color2, 0, 0, 0, 0, 0, 0, interlaced, bevelStyle, bevelPosition, bevelWidth, borderColor, borderWidth);
2167: }
2168:
2169: //====================
2170:
2171: bool MakeGradientEvolved(HDC hdc, RECT rect, LPSTR styleElement, bool drawBevel, bool drawBorder)
2172: {
2173: StyleItem* element = FindStyleElement(styleElement);
2174:
2175: if (element != NULL) // -> Supported style element found!
2176: {
2177: if (!element->parentRelative)
2178: {
2179: // Make sure the requested gradient will actually fit within the target RECT; if not then deny the request...
2180: int borderSpace = element->borderWidth * 2;
2181: int availableSpace = rect.right - rect.left - 4;
2182: if ((borderSpace > availableSpace) || (availableSpace <= 0)) return false;
2183: availableSpace = rect.bottom - rect.top - 4;
2184: if ((borderSpace > availableSpace) || (availableSpace <= 0)) return false;
2185:
2186: // Let's draw the gradient... (including any *regular* border)
2187: // if ((element->type == B_IMAGEFROMFILE) && (element->Image.bitmap != NULL)) DrawImageIntoRect(hdc, rect, element, false, drawBorder);
2188: if ((element->type == B_IMAGEFROMFILE) && (element->Image.bitmap != NULL))
2189: {
2190: /*
2191: if ((element == pSettings->Toolbar) ||
2192: (element == pSettings->MenuTitle) || (element == pSettings->MenuFrame) || (element == pSettings->MenuGrip) ||
2193: (element == pSettings->Dock) ||
2194: (element == pSettings->WindowTitleFocus) || (element == pSettings->WindowTitleUnfocus) ||
2195: (element == pSettings->WindowGripFocus) || (element == pSettings->WindowGripUnfocus) ||
2196: (element == pSettings->WindowHandleFocus) || (element == pSettings->WindowHandleUnfocus))
2197: {
2198: DrawImageIntoRect(hdc, rect, element, false, drawBorder);
2199: }
2200: else DrawImageIntoRect(hdc, rect, element, true, drawBorder); // -> Only allow ARGB image drawing for "non parent" elements (e.g. buttons)
2201: */
2202: if ((element == pSettings->ToolbarButton) || (element == pSettings->ToolbarButtonPressed) ||
2203: (element == pSettings->WindowButtonFocus) || (element == pSettings->WindowButtonPressed) || (element == pSettings->WindowButtonUnfocus))
2204: {
2205: DrawImageIntoRect(hdc, rect, element, true, drawBorder); // -> Only allow ARGB images drawing for button elements (assuming these are always drawn on top of a parent element)
2206: }
2207: else DrawImageIntoRect(hdc, rect, element, false, drawBorder);
2208: }
2209: else if (!drawBevel) MakeGradientSuper(hdc, rect, element->type, element->Color1, element->Color2, element->Color3, element->Color4, element->Color5, element->Color6, element->Color7, element->Color8, element->interlaced, BEVEL_FLAT, 0, 0, element->borderColor, drawBorder ? element->borderWidth : 0);
2210: else MakeGradientSuper(hdc, rect, element->type, element->Color1, element->Color2, element->Color3, element->Color4, element->Color5, element->Color6, element->Color7, element->Color8, element->interlaced, element->bevelstyle, element->bevelposition, pSettings->bevelWidth, element->borderColor, drawBorder ? element->borderWidth : 0);
2211:
2212: // Should we draw a *gradient* border around the gradient? (introduced in xoblite bb5 RC4)
2213: if (drawBorder)
2214: {
2215: StyleItem* elementBorder = NULL;
2216: if ((element == pSettings->Toolbar) && (pSettings->ToolbarBorder->type != B_PARENTRELATIVE)) elementBorder = pSettings->ToolbarBorder;
2217: else if ((element == pSettings->MenuFrame) && (pSettings->MenuFrameBorder->type != B_PARENTRELATIVE)) elementBorder = pSettings->MenuFrameBorder;
2218: else if ((element == pSettings->Dock) && (pSettings->DockBorder->type != B_PARENTRELATIVE)) elementBorder = pSettings->DockBorder;
2219:
2220: if (elementBorder != NULL) CreateBorderSuper(hdc, rect, elementBorder->type, elementBorder->Color1, elementBorder->Color2, elementBorder->Color3, elementBorder->Color4, elementBorder->Color5, elementBorder->Color6, elementBorder->Color7, elementBorder->Color8, element->borderWidth);
2221: }
2222:
2223: return true;
2224: }
2225: else return false; // Style element is parentRelative, nothing drawn...
2226: }
2227: else return false; // -> Unsupported style element, nothing drawn...
2228: }
2229:
2230: //====================
2231:
2232: void MakeStyleGradient(HDC hdc, RECT *rect, StyleItem *item, bool withBorder)
2233: {
2234: // Note: Currently for basic API compatibility only, e.g. not yet accessing StyleItem info beyond "safe" classic 2-colour gradients etc, hence re-parsing via MakeGradient here...
2235: // (read: possibly subject to change later on, pending renewed API version handling across branches? (note: not currently specified in e.g. the StyleItem definition))
2236: if (item->nVersion == CORE_SHELL_STYLEITEM) MakeGradientSuper(hdc, *rect, item->type, item->Color1, item->Color2, item->Color3, item->Color4, item->Color5, item->Color6, item->Color7, item->Color8, item->interlaced, item->bevelstyle, item->bevelposition, 0, pSettings->borderColor, withBorder ? pSettings->borderWidth : 0);
2237: else MakeGradient(hdc, *rect, item->type, item->Color, item->ColorTo, item->interlaced, item->bevelstyle, item->bevelposition, 0, pSettings->borderColor, withBorder ? pSettings->borderWidth : 0);
2238: }
2239:
2240: //===========================================================================
2241: // Functions: CreateBorder / CreateGradientBorder
2242: // Purpose: Draws a border based on the specified input parameters
2243: //===========================================================================
2244:
2245: void CreateBorder(HDC hdc, RECT *rect, int borderColour, int borderWidth)
2246: {
2247: pBImage->DrawBorder(hdc, *rect, borderColour, borderWidth);
2248: }
2249:
2250: //====================
2251:
2252: void CreateBorderSuper(HDC hdc, RECT rect, int type, COLORREF color1, COLORREF color2, COLORREF color3, COLORREF color4, COLORREF color5, COLORREF color6, COLORREF color7, COLORREF color8, int borderWidth)
2253: {
2254: // ##################################################################################################
2255: // ##### BELOW: EXPERIMENTAL SUPPORT FOR GRADIENT BORDERS, NOT YET MEANT FOR PUBLIC CONSUMPTION #####
2256: // ##################################################################################################
2257:
2258: RECT borderRectLeft, borderRectTop, borderRectRight, borderRectBottom;
2259: SetRect(&borderRectLeft, rect.left, rect.top, rect.left + borderWidth, rect.bottom);
2260: SetRect(&borderRectTop, rect.left, rect.top, rect.right, rect.top + borderWidth);
2261: SetRect(&borderRectRight, rect.right - borderWidth, rect.top, rect.right, rect.bottom);
2262: SetRect(&borderRectBottom, rect.left, rect.bottom - borderWidth, rect.right, rect.bottom);
2263:
2264: int overlap = borderWidth - 1;
2265:
2266: if ((type == B_SUPERHORIZONTAL) || (type == B_SPLITHORIZONTAL) || (type == B_MIRRORHORIZONTAL) || (type == B_HORIZONTAL))
2267: {
2268: InflateRect(&borderRectTop, -overlap, 0);
2269: InflateRect(&borderRectBottom, -overlap, 0);
2270:
2271: COLORREF borderColorRight;
2272: if (type == B_SUPERHORIZONTAL) borderColorRight = color8;
2273: else if (type == B_SPLITHORIZONTAL) borderColorRight = color4;
2274: else if (type == B_MIRRORHORIZONTAL) borderColorRight = color1;
2275: else borderColorRight = color2;
2276:
2277: MakeGradientSuper(hdc, borderRectLeft, B_SOLID, color1, 0, 0, 0, 0, 0, 0, 0, false, BEVEL_FLAT, 0, 0, 0, 0);
2278: MakeGradientSuper(hdc, borderRectRight, B_SOLID, borderColorRight, 0, 0, 0, 0, 0, 0, 0, false, BEVEL_FLAT, 0, 0, 0, 0);
2279: MakeGradientSuper(hdc, borderRectTop, type, color1, color2, color3, color4, color5, color6, color7, color8, false, BEVEL_FLAT, 0, 0, 0, 0);
2280: MakeGradientSuper(hdc, borderRectBottom, type, color1, color2, color3, color4, color5, color6, color7, color8, false, BEVEL_FLAT, 0, 0, 0, 0);
2281: }
2282: else if ((type == B_SUPERVERTICAL) || (type == B_SPLITVERTICAL) || (type == B_MIRRORVERTICAL) || (type == B_VERTICAL))
2283: {
2284: InflateRect(&borderRectLeft, 0, -overlap);
2285: InflateRect(&borderRectRight, 0, -overlap);
2286:
2287: COLORREF borderColorBottom;
2288: if (type == B_SUPERVERTICAL) borderColorBottom = color8;
2289: else if (type == B_SPLITVERTICAL) borderColorBottom = color4;
2290: else if (type == B_MIRRORVERTICAL) borderColorBottom = color1;
2291: else borderColorBottom = color2;
2292:
2293: MakeGradientSuper(hdc, borderRectTop, B_SOLID, color1, 0, 0, 0, 0, 0, 0, 0, false, BEVEL_FLAT, 0, 0, 0, 0);
2294: MakeGradientSuper(hdc, borderRectBottom, B_SOLID, borderColorBottom, 0, 0, 0, 0, 0, 0, 0, false, BEVEL_FLAT, 0, 0, 0, 0);
2295: MakeGradientSuper(hdc, borderRectLeft, type, color1, color2, color3, color4, color5, color6, color7, color8, false, BEVEL_FLAT, 0, 0, 0, 0);
2296: MakeGradientSuper(hdc, borderRectRight, type, color1, color2, color3, color4, color5, color6, color7, color8, false, BEVEL_FLAT, 0, 0, 0, 0);
2297: }
2298: }
2299:
2300: //===========================================================================
2301: // Function: CreateElementImage
2302: // Purpose: Creates a GDI HBITMAP from a GDI+ Bitmap image loaded from file
2303: //===========================================================================
2304:
2305: void CreateElementImage(StyleItem* styleItem)
2306: {
2307: if (styleItem->Image.bitmap != NULL) return;
2308:
2309: // if (pSettings->debugLogging) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_WARNING_MESSAGE, (LPARAM)styleItem->Image.path);
2310:
2311: // Load the image using GDI+ to add support for JPG, PNG etc...
2312: // (nb. regular GDI LoadImage() only supports BMP images. GDI+ startup/shutdown is performed "globally" in Blackbox.cpp.)
2313: wchar_t imagePathWC[MAX_PATH];
2314: MultiByteToWideChar(CP_ACP, 0, styleItem->Image.path, strlen(styleItem->Image.path)+1, imagePathWC, MAX_PATH);
2315: Bitmap* bitmap = new Bitmap(imagePathWC, FALSE);
2316:
2317: // ...fetch some of its properties...
2318: styleItem->Image.width = bitmap->GetWidth();
2319: styleItem->Image.height = bitmap->GetHeight();
2320: PixelFormat pf = bitmap->GetPixelFormat();
2321: if ((pf == PixelFormat32bppARGB) || (pf == PixelFormat32bppPARGB) || (pf == PixelFormat64bppARGB) || (pf == PixelFormat64bppPARGB)) styleItem->Image.argb = true;
2322: else styleItem->Image.argb = false;
2323:
2324: // ...and finally create our target GDI HBITMAP from the loaded GDI+ Bitmap...
2325: bitmap->GetHBITMAP(0, &styleItem->Image.bitmap);
2326:
2327: delete bitmap;
2328: }
2329:
2330: //===========================================================================
2331: // Function: DrawImageIntoRect
2332: // Purpose: ...
2333: //===========================================================================
2334:
2335: void DrawImageIntoRect(HDC hdc, RECT r, StyleItem* styleItem, bool useAlpha, bool drawBorder)
2336: {
2337: if (styleItem->Image.bitmap == NULL) return;
2338:
2339: RECT tempRect;
2340: CopyRect(&tempRect, &r);
2341:
2342: if (drawBorder)
2343: {
2344: // Draw border...
2345: CreateBorder(hdc, &tempRect, styleItem->borderColor, styleItem->borderWidth);
2346: InflateRect(&tempRect, -styleItem->borderWidth, -styleItem->borderWidth);
2347: }
2348:
2349: // Draw image...
2350: HDC buf = CreateCompatibleDC(hdc);
2351: DeleteObject(SelectObject(buf, styleItem->Image.bitmap));
2352: SetStretchBltMode(hdc, HALFTONE);
2353:
2354: int itemWidth = tempRect.right - tempRect.left;
2355: int itemHeight = tempRect.bottom - tempRect.top;
2356: int edgesLeftRight = styleItem->Image.left + styleItem->Image.right;
2357: int edgesTopBottom = styleItem->Image.top + styleItem->Image.bottom;
2358:
2359: if (useAlpha && styleItem->Image.argb) // -> Should we draw an ARGB image using alpha blending on top of something else? (e.g. menu bullets)
2360: {
2361: // ### Note: While AlphaBlend() can be used to draw 32bpp ARGB images with per pixel alpha transparency, it also scales images down
2362: // much less smoothly than StretchBlt() as it reverts from HALFTONE (i.e. pixel averaging) to COLORONCOLOR (i.e. pixel deleting) mode;
2363: // for more information see https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-alphablend ###
2364: BLENDFUNCTION bf;
2365: ZeroMemory(&bf, sizeof(BLENDFUNCTION));
2366: bf.BlendOp = AC_SRC_OVER;
2367: bf.BlendFlags = 0;
2368: bf.SourceConstantAlpha = 255;
2369: bf.AlphaFormat = AC_SRC_ALPHA;
2370: AlphaBlend(hdc, tempRect.left, tempRect.top, itemWidth, itemHeight, buf, 0, 0, styleItem->Image.width, styleItem->Image.height, bf);
2371: }
2372: else // -> If not, use the regular BitBlt/StretchBlt functions for RGB images as these provide better scaling quality... (see explanation above)
2373: {
2374: if ((styleItem->Image.width < edgesLeftRight) || (styleItem->Image.height < edgesTopBottom))
2375: {
2376: StretchBlt(hdc, tempRect.left, tempRect.top, itemWidth, itemHeight, buf, 0, 0, styleItem->Image.width, styleItem->Image.height, SRCCOPY);
2377: }
2378: else
2379: {
2380: if (styleItem->Image.left > 0)
2381: {
2382: if (styleItem->Image.top > 0) BitBlt(hdc, tempRect.left, tempRect.top, styleItem->Image.left, styleItem->Image.top, buf, 0, 0, SRCCOPY);
2383: if (styleItem->Image.bottom > 0) BitBlt(hdc, tempRect.left, (tempRect.bottom-styleItem->Image.bottom), styleItem->Image.left, styleItem->Image.bottom, buf, 0, (styleItem->Image.height-styleItem->Image.bottom), SRCCOPY);
2384: StretchBlt(hdc, tempRect.left, (tempRect.top+styleItem->Image.top), styleItem->Image.left, (itemHeight-edgesTopBottom), buf, 0, styleItem->Image.top, styleItem->Image.left, (styleItem->Image.height-edgesTopBottom), SRCCOPY);
2385: }
2386:
2387: if (styleItem->Image.right > 0)
2388: {
2389: if (styleItem->Image.top > 0) BitBlt(hdc, tempRect.right-styleItem->Image.right, tempRect.top, styleItem->Image.right, styleItem->Image.top, buf, (styleItem->Image.width-styleItem->Image.right), 0, SRCCOPY);
2390: if (styleItem->Image.bottom > 0) BitBlt(hdc, tempRect.right-styleItem->Image.right, (tempRect.bottom-styleItem->Image.bottom), styleItem->Image.right, styleItem->Image.bottom, buf, (styleItem->Image.width-styleItem->Image.right), (styleItem->Image.height-styleItem->Image.bottom), SRCCOPY);
2391: StretchBlt(hdc, tempRect.right-styleItem->Image.right, (tempRect.top+styleItem->Image.top), styleItem->Image.right, (itemHeight-edgesTopBottom), buf, (styleItem->Image.width-styleItem->Image.right), styleItem->Image.top, styleItem->Image.right, (styleItem->Image.height-edgesTopBottom), SRCCOPY);
2392: }
2393:
2394: if (styleItem->Image.top > 0)
2395: {
2396: if (styleItem->Image.left > 0) BitBlt(hdc, tempRect.left, tempRect.top, styleItem->Image.left, styleItem->Image.top, buf, 0, 0, SRCCOPY);
2397: if (styleItem->Image.right > 0) BitBlt(hdc, tempRect.right-styleItem->Image.right, tempRect.top, styleItem->Image.right, styleItem->Image.top, buf, (styleItem->Image.width-styleItem->Image.right), 0, SRCCOPY);
2398: StretchBlt(hdc, (tempRect.left+styleItem->Image.left), tempRect.top, (itemWidth-edgesLeftRight), (tempRect.top+styleItem->Image.top), buf, styleItem->Image.left, 0, (styleItem->Image.width-edgesLeftRight), styleItem->Image.top, SRCCOPY);
2399: }
2400:
2401: if (styleItem->Image.bottom > 0)
2402: {
2403: if (styleItem->Image.left > 0) BitBlt(hdc, tempRect.left, (tempRect.bottom-styleItem->Image.bottom), styleItem->Image.left, styleItem->Image.bottom, buf, 0, (styleItem->Image.height-styleItem->Image.bottom), SRCCOPY);
2404: if (styleItem->Image.right > 0) BitBlt(hdc, tempRect.right-styleItem->Image.right, (tempRect.bottom-styleItem->Image.bottom), styleItem->Image.right, styleItem->Image.bottom, buf, (styleItem->Image.width-styleItem->Image.right), (styleItem->Image.height-styleItem->Image.bottom), SRCCOPY);
2405: StretchBlt(hdc, (tempRect.left+styleItem->Image.left), (tempRect.bottom-styleItem->Image.bottom), (itemWidth-edgesLeftRight), styleItem->Image.bottom, buf, styleItem->Image.left, (styleItem->Image.height-styleItem->Image.bottom), (styleItem->Image.width-edgesLeftRight), styleItem->Image.bottom, SRCCOPY);
2406: }
2407:
2408: StretchBlt(hdc, (tempRect.left+styleItem->Image.left), (tempRect.top+styleItem->Image.top), (itemWidth-edgesLeftRight), (itemHeight-edgesTopBottom), buf, styleItem->Image.left, styleItem->Image.top, (styleItem->Image.width-edgesLeftRight), (styleItem->Image.height-edgesTopBottom), SRCCOPY);
2409: }
2410: }
2411:
2412: DeleteDC(buf);
2413: }
2414:
2415: //===========================================================================
2416: // Functions: AlphaRect/AlphaBorder/AlphaCorner/AlphaMask/AlphaApply
2417: // Purpose: Per pixel alpha transparency function (introduced in xoblite bb4)
2418: // Function: AlphaCornerEvolved
2419: // Purpose: Per pixel alpha transparency function (introduced in xoblite bb5)
2420: //===========================================================================
2421:
2422: void AlphaRect(HDC hdc, RECT rect, unsigned char alpha)
2423: {
2424: // Note: Use alpha == 255 as input value to remove
2425: // per pixel alpha i.e. make the rect fully opaque.
2426: pBImage->AlphaRect(hdc, rect, alpha);
2427: }
2428:
2429: void AlphaBorder(HDC hdc, RECT rect, unsigned char alpha, int borderWidth)
2430: {
2431: pBImage->AlphaBorder(hdc, rect, alpha, borderWidth);
2432: }
2433:
2434: void AlphaCorner(HDC hdc, RECT rect, int corner, int bevelStyle, int bevelPosition, int bevelWidth, int borderWidth, unsigned char minAlpha, unsigned char maxAlpha)
2435: {
2436: // Note: All input parameters are not currently used, but have been included
2437: // in the function definition to avoid API changes if/when the implementation
2438: // is improved (which is tricky given the numerous rendering options available)
2439: pBImage->AlphaCorner(hdc, rect, corner, borderWidth, minAlpha, maxAlpha);
2440: }
2441:
2442: void AlphaFromRGB(HDC hdc, RECT rect, unsigned char minAlpha, unsigned char maxAlpha, bool recolor, COLORREF color)
2443: {
2444: pBImage->AlphaFromRGB(hdc, rect, minAlpha, maxAlpha, recolor, color);
2445: }
2446:
2447: void AlphaMask(HDC destHdc, RECT destRect, HDC srcHdc, RECT srcRect, bool useSrcRGBAsAlpha)
2448: {
2449: pBImage->AlphaMask(destHdc, destRect, srcHdc, srcRect, useSrcRGBAsAlpha);
2450: }
2451:
2452: void AlphaApply(HDC hdc, RECT rect)
2453: {
2454: // "AlphaApplyToRGB"
2455: // -> Pre-applies the per pixel alpha to the RGB values of each pixel
2456: // (required by related Windows API functions before processing).
2457: pBImage->AlphaApply(hdc, rect);
2458: }
2459:
2460: //===========================================================================
2461: // Functions: PrepareCorner / PrepareCornerEvolved
2462: // Purpose: Rounding off of pixel data before call to AlphaCorner (see above)
2463: //===========================================================================
2464:
2465: void PrepareCorner(HDC hdc, RECT rect, int corner, int bevelStyle, int bevelPosition, int bevelWidth, int borderWidth)
2466: {
2467: pBImage->PrepareCorner(hdc, rect, corner, bevelStyle, bevelPosition, bevelWidth, borderWidth);
2468: }
2469:
2470: int PrepareCornerEvolved(HDC hdc, RECT rect, int corner, LPSTR styleElement)
2471: {
2472: StyleItem* element = FindStyleElement(styleElement);
2473: if (element != NULL)
2474: {
2475: pBImage->PrepareCorner(hdc, rect, corner, element->bevelstyle, element->bevelposition, 1, element->borderWidth);
2476: return element->borderWidth;
2477: }
2478: else return 0;
2479: }
2480:
2481: //===========================================================================
2482: // Functions: EnumFontFamProc/CreateStyleFont
2483: // Purpose: ...
2484: //===========================================================================
2485:
2486: static int CALLBACK EnumFontFamProc(
2487: ENUMLOGFONT *lpelf, // Pointer to logical font data
2488: NEWTEXTMETRIC *lpntm, // Pointer to physical font data
2489: int FontType, // Type of font
2490: LPARAM lParam // Address of application defined data
2491: )
2492: {
2493: (*(int*)lParam)++;
2494: return 0;
2495: }
2496:
2497: //====================
2498:
2499: HFONT CreateStyleFont(StyleItem *item)
2500: {
2501: char *face = item->Font;
2502: int height = item->FontHeight;
2503: int weight = item->FontWeight;
2504:
2505: HDC hdc = CreateCompatibleDC(NULL);
2506: int data = 0;
2507: EnumFontFamilies(hdc, face, (FONTENUMPROC)EnumFontFamProc, (LPARAM)&data);
2508: DeleteDC(hdc);
2509: if (!data) face = "verdana";
2510:
2511: return CreateFont(height, 0, 0, 0, weight, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, face);
2512: }
2513:
2514: //===========================================================================
2515: // Function: IsInString / IsInStringUnicode
2516: // Purpose: Checks a given string to an occurance of the second string
2517: // In: LPCSTR / LPWSTR = string to search
2518: // In: LPCSTR / LPWSTR = string to search for
2519: // Out: bool = found or not
2520: //===========================================================================
2521:
2522: bool IsInString(LPCSTR inputString, LPCSTR searchString)
2523: {
2524: // StrStrIA -> ANSI version of StrStrI, a case insensitive strstr (Win32 shlwapi.lib)
2525: if (StrStrIA(inputString, searchString) != NULL) return true;
2526: else return false;
2527: }
2528:
2529: bool IsInStringUnicode(LPWSTR inputString, LPWSTR searchString)
2530: {
2531: // StrStrIW -> Unicode version of StrStrI, a case insensitive strstr (Win32 shlwapi.lib)
2532: if (StrStrIW(inputString, searchString) != NULL) return true;
2533: else return false;
2534: }
2535:
2536: //===========================================================================
2537: // Function: ParseItem
2538: // Purpose: parses a given string and assigns settings to a StyleItem class
2539: // In: LPCSTR = item to parse out
2540: // In: StyleItem* = class to assign values to
2541: // Out: void = None
2542: //===========================================================================
2543:
2544: void ParseItem(LPCSTR szItem, StyleItem *item)
2545: {
2546: // Default settings
2547: item->type = B_SOLID;
2548: item->bevelstyle = BEVEL_FLAT;
2549: item->bevelposition = BEVEL1;
2550: item->parentRelative = false;
2551: item->interlaced = false;
2552:
2553: if (strchr(szItem, '\\') || IsInString(szItem, "image")) // -> Simple (path in .appearance), or more advanced (path in .image, plus related options specified in .appearance)
2554: {
2555: item->type = B_IMAGEFROMFILE;
2556: return;
2557: }
2558:
2559: if (IsInString(szItem, "solid")) item->type = B_SOLID;
2560: else if (IsInString(szItem, "vertical")) item->type = B_VERTICAL;
2561: else if (IsInString(szItem, "horizontal")) item->type = B_HORIZONTAL;
2562: else if (IsInString(szItem, "crossdiagonal")) item->type = B_CROSSDIAGONAL; // Must be checked before diagonal!
2563: else if (IsInString(szItem, "diagonal")) item->type = B_DIAGONAL;
2564: else if (IsInString(szItem, "pipecross")) item->type = B_PIPECROSS;
2565: else if (IsInString(szItem, "elliptic")) item->type = B_ELLIPTIC;
2566: else if (IsInString(szItem, "rectangle")) item->type = B_RECTANGLE;
2567: else if (IsInString(szItem, "pyramid")) item->type = B_PYRAMID;
2568:
2569: if (IsInString(szItem, "split")) item->type += 100; // 4-colour "split" gradients (i.e. SplitHorizontal/SplitVertical)
2570: else if (IsInString(szItem, "super")) item->type += 150; // 8-colour "super" gradients (i.e. SuperHorizontal/SuperVertical)
2571: else if (IsInString(szItem, "mirror")) item->type += 200; // 2-colour "mirrored" gradients (i.e. MirrorHorizontal/MirrorVertical)
2572:
2573: if (IsInString(szItem, "flat")) item->bevelstyle=BEVEL_FLAT;
2574: else if (IsInString(szItem, "raised")) item->bevelstyle=BEVEL_RAISED;
2575: else if (IsInString(szItem, "sunken")) item->bevelstyle=BEVEL_SUNKEN;
2576:
2577: if (IsInString(szItem, "bevel2")) item->bevelposition=BEVEL2;
2578: else if (IsInString(szItem, "bevel1")) item->bevelposition=BEVEL1;
2579:
2580: if (IsInString(szItem, "interlaced")) item->interlaced = true;
2581:
2582: if (IsInString(szItem, "parentrelative"))
2583: {
2584: item->type = B_PARENTRELATIVE;
2585: item->parentRelative = true;
2586: }
2587: }
2588:
2589: //===========================================================================
2590: // Function: ReplaceEnvVars
2591: // Purpose: parses a given string and replaces all %VAR% with the environment
2592: // variable value if such a value exists
2593: // In: LPSTR = string to replace env vars in
2594: // Out: void = None
2595: //===========================================================================
2596:
2597: void ReplaceEnvVars(LPSTR string)
2598: {
2599: LPSTR pos0 = string, pos1 = strchr(pos0+1,'%');
2600: if (pos1 == NULL) return; // Failsafe (only a single % character found in the string)
2601:
2602: while ((pos0 = strchr(pos0,'%')) && (pos1 = strchr(++pos0,'%')))
2603: {
2604: if (pos0 == pos1) continue; // ...this means that we have "%%"
2605:
2606: char var_name[MAX_LINE_LENGTH]="", var_value[MAX_LINE_LENGTH]="";
2607: memcpy(var_name,pos0,pos1-pos0);
2608:
2609: // Grab the variable name(s) from the string...
2610: int nSize = GetEnvironmentVariable(var_name, var_value, MAX_LINE_LENGTH);
2611: if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2612: {
2613: SetLastError(ERROR_SUCCESS);
2614: continue;
2615: }
2616:
2617: if ((nSize + strlen(string) + 1 - (pos1-pos0+2)) > MAX_LINE_LENGTH)
2618: {
2619: //TODO signal some sort of error
2620: continue;
2621: }
2622:
2623: // Perform the substitution...
2624: memmove(pos0-1+nSize,pos1+1,strlen(pos1)+1); // Don't forget the \0 !!!
2625: memcpy(pos0-1,var_value,nSize);
2626: }
2627: }
2628:
2629: //===========================================================================
2630: // Function: ReplaceShellFolders
2631: // Purpose:
2632: // In: LPSTR = string to replace shell folders in
2633: // Out: void = None
2634: //===========================================================================
2635:
2636: void ReplaceShellFolders(LPSTR string)
2637: {
2638: LPSTR pos0 = string, pos1 = strchr(pos0+1,'$');
2639: if (pos1 == NULL) return; // Failsafe (only a single $ character found in the string)
2640:
2641: char folderpath[MAX_LINE_LENGTH];
2642:
2643: while ((pos0 = strchr(pos0,'$')) && (pos1 = strchr(pos0+1,'$')))
2644: {
2645: if(pos0 == pos1) continue; // ...this means that we have "$$"
2646:
2647: // Note that there can be more than one shell folder
2648: // variable in a string, check current position only!
2649: if (!_strnicmp(pos0, "$ProgramFiles$", 14)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_programFiles);
2650: else if (!_strnicmp(pos0, "$ProgramFilesX86$", 17)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_programFilesX86);
2651: else if (!_strnicmp(pos0, "$Blackbox$", 10)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_blackboxPath);
2652: else if (!_strnicmp(pos0, "$CurrentTheme$", 14)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_currentThemePath);
2653: else if (!_strnicmp(pos0, "$StartMenu$", 11)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_startMenu);
2654: else if (!_strnicmp(pos0, "$CommonStartMenu$", 17)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_commonStartMenu);
2655: else if (!_strnicmp(pos0, "$Desktop$", 9)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_desktop);
2656: else if (!_strnicmp(pos0, "$UserAppData$", 13)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_userAppData);
2657: else if (!_strnicmp(pos0, "$UserProfile$", 13)) strcpy_s(folderpath, sizeofArray(folderpath), pSettings->SF_userProfile);
2658: else if (!_strnicmp(pos0, "$Clipboard$", 11)) RetrieveStringFromClipboard(folderpath);
2659: else folderpath[0] = '\0'; // Failsafe
2660:
2661: memmove(pos0+strnlen_s(folderpath, sizeofArray(folderpath)), pos1+1, strlen(pos1)+1); // Don't forget the \0 !!!
2662: memcpy(pos0, folderpath, strnlen_s(folderpath, sizeofArray(folderpath)));
2663: }
2664: }
2665:
2666: //===========================================================================
2667: // Function: ParseFontString
2668: // Purpose: Parses a Name/Height/WeightOutlineShadow format font string
2669: // In: LPSTR string, StyleItem *item
2670: // Out: void = None
2671: //===========================================================================
2672:
2673: void ParseFontString(LPSTR string, StyleItem *item)
2674: {
2675: char height[MAX_LINE_LENGTH];
2676: strcpy_s(tempBuf, sizeofArray(tempBuf), string);
2677:
2678: strcpy_s(tempBuf, sizeofArray(tempBuf), Tokenize(tempBuf, item->Font, "/"));
2679: CheckFontSubstitution(item->Font);
2680:
2681: if (strnlen_s(tempBuf, sizeofArray(tempBuf)))
2682: {
2683: strcpy_s(tempBuf, sizeofArray(tempBuf), Tokenize(tempBuf, height, "/"));
2684: item->FontHeight = atoi(height);
2685:
2686: if (IsInString(tempBuf, "Bold")) item->FontWeight = FW_BOLD;
2687: else item->FontWeight = FW_NORMAL;
2688:
2689: if (IsInString(tempBuf, "Outline")) item->FontOutline = true;
2690: else item->FontOutline = false;
2691:
2692: if (IsInString(tempBuf, "Shadow")) item->FontShadow = true;
2693: else item->FontShadow = false;
2694: }
2695: else
2696: {
2697: item->FontHeight = 12;
2698: item->FontWeight = FW_NORMAL;
2699: item->FontOutline = item->FontShadow = false;
2700: }
2701: }
2702:
2703: //===========================================================================
2704: // Function: CheckFontSubstitution
2705: // Purpose: Replaces *nix-only fonts with (hopefully) Windows equivalents
2706: // In: LPSTR = string to replace font names in
2707: // Out: void = None
2708: //===========================================================================
2709:
2710: void CheckFontSubstitution(LPSTR font)
2711: {
2712: // We can save a few IsInString's by checking for "-" in the font name...
2713: if (strchr(font, '-'))
2714: {
2715: if (IsInString(font, "lucidasans-")) strcpy(font, "verdana");
2716: else if (IsInString(font, "-lucidatypewriter-")) strcpy(font, "verdana");
2717: else if (IsInString(font, "-lucida-")) strcpy(font, "verdana");
2718: else if (IsInString(font, "-snap-")) strcpy(font, "snap");
2719: else if (IsInString(font, "-verdana-")) strcpy(font, "verdana");
2720: else if (IsInString(font, "-helvetica-")) strcpy(font, "verdana");
2721: else if (IsInString(font, "-arial-")) strcpy(font, "arial");
2722: }
2723: else
2724: {
2725: if (IsInString(font, "lucidatypewriter")) strcpy(font, "verdana");
2726: else if (IsInString(font, "helvetica")) strcpy(font, "verdana");
2727: else if (IsInString(font, "fixed")) strcpy(font, "terminal");
2728: }
2729:
2730: // No idea what to substitute with:
2731: // shine -beatbox- bright outcast -clean- seeds
2732: }
2733:
2734: //===========================================================================
2735: // Functions: MakeMenu/MakeNamedMenu/MakeSubmenu/DelMenu
2736: // Purpose: Various menu handling functions
2737: //===========================================================================
2738:
2739: Menu *MakeMenu(LPCSTR HeaderText)
2740: {
2741: Menu *newMenu = new Menu(pMenuCommon->hInst);
2742: pMenuCommon->AddHeaderItem(newMenu, (LPSTR)HeaderText);
2743: return newMenu;
2744: }
2745:
2746: //====================
2747:
2748: Menu *MakeNamedMenu(LPCSTR HeaderText, LPCSTR MenuId, bool popup)
2749: {
2750: if (popup)
2751: {
2752: hideNamedMenu = false;
2753: return MakeMenu(HeaderText);
2754: }
2755: else
2756: {
2757: hideNamedMenu = true;
2758: return NULL;
2759: }
2760: }
2761:
2762: /*
2763: Menu* namedPluginMenu = NULL;
2764: char currentNamedMenu[MAX_LINE_LENGTH] = "\0";
2765:
2766: Menu *MakeNamedMenu(LPCSTR HeaderText, LPCSTR MenuId, bool popup)
2767: {
2768: if (popup)
2769: {
2770: hideNamedMenu = false;
2771:
2772: // Does the newly requested named menu have the same ID as the previous one?
2773: if (!_stricmp(MenuId, currentNamedMenu))
2774: {
2775: if (namedPluginMenu != NULL) return namedPluginMenu;
2776: else
2777: {
2778: namedPluginMenu = MakeMenu(HeaderText);
2779: strncpy(currentNamedMenu, MenuId, MAX_LINE_LENGTH-1);
2780: return namedPluginMenu;
2781: }
2782: }
2783: else // -> Another named menu is requested...
2784: {
2785: if (namedPluginMenu != NULL) DelMenu(namedPluginMenu);
2786: namedPluginMenu = NULL;
2787:
2788: return MakeMenu(HeaderText);
2789: }
2790: }
2791: else
2792: {
2793: hideNamedMenu = true;
2794: return NULL;
2795: }
2796: }
2797: */
2798:
2799: //====================
2800:
2801: MenuItem *MakeSubmenu(Menu *ParentMenu, Menu *ChildMenu, LPCSTR Title)
2802: {
2803: if (!ParentMenu) return NULL;
2804:
2805: MenuItem *newMenuItem = NULL;
2806:
2807: if (ChildMenu)
2808: {
2809: pMenuCommon->AddFooterItem(ChildMenu, "");
2810:
2811: ChildMenu->Invalidate();
2812: ChildMenu->Validate();
2813:
2814: if (ParentMenu)
2815: {
2816: newMenuItem = new FolderItem(ChildMenu, (LPSTR)Title, NULL);
2817: newMenuItem->SetHeight(pMenuCommon->m_nSubmenuHeight);
2818: ParentMenu->AddMenuItem(newMenuItem);
2819: }
2820: }
2821:
2822: return newMenuItem;
2823: }
2824:
2825: //====================
2826:
2827: void DelMenu(Menu* PluginMenu)
2828: {
2829: if (PluginMenu == pMenuCommon->m_pPluginMenu)
2830: {
2831: delete pMenuCommon->m_pPluginMenu;
2832: pMenuCommon->m_pPluginMenu = NULL;
2833: }
2834: }
2835:
2836: //===========================================================================
2837: // Functions: MakeMenuItem / MakeMenuItemBool / MakeMenuNOP /
2838: // MakeMenuItemString / MakeMenuItemInt
2839: // Purpose: Various menu item creation functions
2840: //===========================================================================
2841:
2842: MenuItem *MakeMenuItem(Menu *PluginMenu, LPCSTR Title, LPCSTR Cmd, bool ShowIndicator)
2843: {
2844: if (!PluginMenu) return NULL;
2845: // if (strchr(Cmd, '[') && strchr(Cmd, ']')) pMenuCommon->CreateMenuItem(PluginMenu, (LPSTR)Cmd, (LPSTR)Cmd, (LPSTR)Title, ShowIndicator);
2846: // else pMenuCommon->CreateMenuItem(PluginMenu, "[exec]", (LPSTR)Cmd, (LPSTR)Title, ShowIndicator);
2847: return pMenuCommon->CreateMenuItem(PluginMenu, MENUITEM_COMMAND, "[exec]", (LPSTR)Cmd, (LPSTR)Title, ShowIndicator);
2848: }
2849:
2850: MenuItem* MakeMenuItemBool(Menu* PluginMenu, LPCSTR Title, LPCSTR Cmd, bool state, int selectionGroup)
2851: {
2852: if (!PluginMenu) return NULL;
2853: MenuItem* newItem = pMenuCommon->CreateMenuItem(PluginMenu, MENUITEM_BOOLEAN, "[exec]", (LPSTR)Cmd, (LPSTR)Title, state);
2854: if (selectionGroup > 0) newItem->AddToSelectionGroup((1000+selectionGroup)); // Add the new menu item to a mutually exclusive group of boolean items (nb. often useful for e.g. placement menus where only one item is "true" at a time)
2855: return newItem;
2856: }
2857:
2858: //====================
2859:
2860: MenuItem *MakeMenuNOP(Menu *PluginMenu, LPCSTR Title)
2861: {
2862: if (!PluginMenu) return NULL;
2863:
2864: if (Title != NULL)
2865: {
2866: if (!_strnicmp(Title, "---", 3)) // If the first three characters are --- we convert the NOP into a separator
2867: {
2868: if (!pSettings->menuSeparators) return NULL;
2869: else return pMenuCommon->CreateMenuItem(PluginMenu, MENUITEM_SEPARATOR, NULL, NULL, (LPSTR)Title, false);
2870: }
2871: }
2872:
2873: return pMenuCommon->CreateMenuItem(PluginMenu, MENUITEM_NOP, NULL, NULL, (LPSTR)Title, false);
2874: }
2875:
2876: //====================
2877:
2878: MenuItem *MakeMenuItemString(Menu *PluginMenu, LPCSTR Title, LPCSTR Cmd, LPCSTR init_string)
2879: {
2880: if (!PluginMenu) return NULL;
2881:
2882: char TitleColonInitString[MAX_LINE_LENGTH];
2883:
2884: if (strlen(Title) > 0)
2885: {
2886: if ((strlen(Title) >= 3) && !_strnicmp(&Title[strlen(Title)-3], "...", 3))
2887: {
2888: // Hidden init_string -> Just copy the title...
2889: strcpy_s(TitleColonInitString, sizeofArray(TitleColonInitString), Title);
2890: }
2891: else
2892: {
2893: // Visible init_string -> Make sure there's a colon after the title for consistency... :)
2894: if (Title[strlen(Title)-1] == ':') sprintf_s(TitleColonInitString, sizeofArray(TitleColonInitString), "%s <%s>", Title, init_string);
2895: else sprintf_s(TitleColonInitString, sizeofArray(TitleColonInitString), "%s: <%s>", Title, init_string);
2896: }
2897: }
2898: else sprintf_s(TitleColonInitString, sizeofArray(TitleColonInitString), "<%s>", init_string); // No title specified, so no colon needed...
2899:
2900: return pMenuCommon->CreateMenuItem(PluginMenu, MENUITEM_EDITSTRING, (LPSTR)Cmd, (LPSTR)init_string, (LPSTR)TitleColonInitString, false);
2901: }
2902:
2903: //====================
2904:
2905: MenuItem *MakeMenuItemInt(Menu *PluginMenu, LPCSTR Title, LPCSTR Cmd, int val, int minval, int maxval)
2906: {
2907: if (!PluginMenu) return NULL;
2908:
2909: char TitleWithColon [MAX_LINE_LENGTH], CmdValues[MAX_LINE_LENGTH];
2910:
2911: // Make sure there's a colon after the title for consistency... :)
2912: if (Title[strlen(Title)-1] == ':') sprintf_s(TitleWithColon, sizeofArray(TitleWithColon), "%s", Title);
2913: else sprintf_s(TitleWithColon, sizeofArray(TitleWithColon), "%s:", Title);
2914: // Does the command string includes spaces?
2915: if (strstr(Cmd, " ")) sprintf_s(CmdValues, sizeofArray(CmdValues), "\"%s\" %d %d %d", Cmd, val, minval, maxval);
2916: else sprintf_s(CmdValues, sizeofArray(CmdValues), "%s %d %d %d", Cmd, val, minval, maxval);
2917:
2918: bool enabled = false;
2919: // if ((val>=minval) && (val<=maxval)) enabled = true;
2920:
2921: return pMenuCommon->CreateMenuItem(PluginMenu, MENUITEM_EDITINT, (LPSTR)CmdValues, NULL, (LPSTR)TitleWithColon, enabled);
2922: }
2923:
2924: //===========================================================================
2925: // Function: ShowMenu
2926: // Purpose: ...
2927: //===========================================================================
2928:
2929: void ShowMenu(Menu *PluginMenu)
2930: {
2931: if (!PluginMenu) return;
2932:
2933: //====================
2934:
2935: if (hideNamedMenu && pMenuCommon->m_pPluginMenu)
2936: {
2937: if (PluginMenu == pMenuCommon->m_pPluginMenu)
2938: {
2939: // pMenuCommon->Hide();
2940: pMenuCommon->m_pPluginMenu->Hide(HIDE_CHILDREN);
2941: ShowWindow(pMenuCommon->m_pPluginMenu->GetWindow(), SW_HIDE);
2942: DelMenu(pMenuCommon->m_pPluginMenu);
2943: }
2944: hideNamedMenu = false;
2945: return;
2946: }
2947:
2948: //====================
2949:
2950: pMenuCommon->Hide();
2951: if (pMenuCommon->m_pPluginMenu) DelMenu(pMenuCommon->m_pPluginMenu);
2952: pMenuCommon->m_pPluginMenu = PluginMenu;
2953:
2954: pMenuCommon->AddFooterItem(PluginMenu, "");
2955:
2956: PluginMenu->Invalidate();
2957: PluginMenu->Validate();
2958:
2959: PluginMenu->Show();
2960: PlaySoundFX(SFX_MENU_SHOW);
2961: }
2962:
2963: //===========================================================================
2964: // Functions: MakeSticky/RemoveSticky/CheckSticky/ClearSticky
2965: // Purpose: Provides "sticky windows" functionality
2966: // (where sticky windows are visible on *all* workspaces)
2967: //===========================================================================
2968:
2969: void MakeSticky(HWND window)
2970: {
2971: stickyWindows.push_back(window); // Note: This step applies also to non-taskbar windows...
2972:
2973: if (pTaskbar)
2974: {
2975: int i = pTaskbar->FindTask(window);
2976: if (i >= 0) pTaskbar->taskList[i]->workspace = 254; // Making the window sticky -> "Visible on all workspaces"
2977: }
2978: }
2979:
2980: //====================
2981:
2982: void RemoveSticky(HWND window)
2983: {
2984: for (int i=0; i < (int)stickyWindows.size(); i++)
2985: {
2986: if (stickyWindows[i] == window) stickyWindows.erase(stickyWindows.begin() + i); // Note: This step applies also to non-taskbar windows...
2987: }
2988:
2989: if (pTaskbar)
2990: {
2991: int i = pTaskbar->FindTask(window);
2992: if (i >= 0) pTaskbar->taskList[i]->workspace = pSettings->currentWorkspace; // Making the window non-sticky -> "Visible only on this particular workspace"
2993: }
2994: }
2995:
2996: //====================
2997:
2998: bool CheckSticky(HWND window)
2999: {
3000: for (int i=0; i < (int)stickyWindows.size(); i++)
3001: {
3002: if (stickyWindows[i] == window) return true; // Note: This step applies also to non-taskbar windows...
3003: }
3004:
3005: return false;
3006: }
3007:
3008: //====================
3009:
3010: void ToggleSticky(HWND window)
3011: {
3012: if (!CheckSticky(window)) MakeSticky(window);
3013: else RemoveSticky(window);
3014: }
3015:
3016: //====================
3017:
3018: void ClearSticky()
3019: {
3020: stickyWindows.clear(); // Clean up...
3021: }
3022:
3023: //===========================================================================
3024: // Functions: SetTransparencyEx/SetTransparency
3025: // Purpose: Configures basic window-level alpha transparency
3026: //===========================================================================
3027:
3028: typedef bool (__stdcall *slwaFunc)(HWND, COLORREF, BYTE, DWORD);
3029:
3030: bool SetTransparencyEx(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags)
3031: {
3032: slwaFunc SLWA = (slwaFunc)GetProcAddress(GetModuleHandle("USER32"), "SetLayeredWindowAttributes");
3033: if (!SLWA) return false;
3034:
3035: //====================
3036:
3037: if (dwFlags == LWA_ALPHA)
3038: {
3039: if (bAlpha < 255)
3040: {
3041: LONG windowStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
3042: windowStyle = windowStyle | WS_EX_LAYERED;
3043: SetWindowLong(hwnd, GWL_EXSTYLE, windowStyle);
3044: return SLWA(hwnd, NULL, bAlpha, LWA_ALPHA);
3045: }
3046: else
3047: {
3048: LONG windowStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
3049: windowStyle = windowStyle & ~WS_EX_LAYERED;
3050: SetWindowLong(hwnd, GWL_EXSTYLE, windowStyle);
3051: return false;
3052: }
3053: }
3054:
3055: //====================
3056:
3057: else if (dwFlags == LWA_COLORKEY)
3058: {
3059: LONG windowStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
3060: windowStyle = windowStyle | WS_EX_LAYERED;
3061: SetWindowLong(hwnd, GWL_EXSTYLE, windowStyle);
3062: return SLWA(hwnd, crKey, 255, LWA_COLORKEY);
3063: }
3064:
3065: //====================
3066:
3067: return false;
3068: }
3069:
3070: //====================
3071:
3072: bool SetTransparency(HWND hwnd, BYTE alpha)
3073: {
3074: return SetTransparencyEx(hwnd, 0, alpha, LWA_ALPHA);
3075: }
3076:
3077: //===========================================================================
3078: // Functions: WriteValue/WriteBool/WriteInt/WriteString/WriteColor
3079: // Purpose: ...
3080: //===========================================================================
3081:
3082: void WriteValue(LPCSTR fp, LPCSTR keyword, LPCSTR value)
3083: {
3084: if (pSettings)
3085: {
3086: if (pSettings->writeProtection) return;
3087: }
3088:
3089: vector <string> fileContents;
3090: char fileLine[MAX_LINE_LENGTH];
3091: int pointer;
3092: bool written = false;
3093:
3094: FILE *file = fopen(fp, "r");
3095: if (file)
3096: {
3097: fseek(file, 0, SEEK_SET);
3098: while (fgets(fileLine, sizeof(fileLine)-2, file))
3099: {
3100: if (!IsInString(fileLine, "\n")) strcat_s(fileLine, sizeofArray(fileLine), "\n");
3101: fileLine[sizeof(fileLine)-1] = '\0'; // Additional failsafe
3102:
3103: // Check for the specified keyword, disregarding lines beginning with ! (comments)
3104: if (IsInString(fileLine, keyword) && fileLine[0] != '!')
3105: {
3106: sprintf_s(fileLine, sizeofArray(fileLine), "%s %s\n", keyword, value);
3107: written = true;
3108: }
3109:
3110: fileContents.push_back(fileLine);
3111: }
3112: fclose(file);
3113: }
3114:
3115: if (!written)
3116: {
3117: sprintf_s(fileLine, sizeofArray(fileLine), "%s %s\n", keyword, value);
3118: fileContents.push_back(fileLine);
3119: }
3120:
3121: file = fopen(fp, "w");
3122: if (file)
3123: {
3124: fseek(file, 0, SEEK_SET);
3125: for (pointer = 0; pointer < (int)fileContents.size(); pointer++)
3126: {
3127: fputs(fileContents[pointer].c_str(), file);
3128: }
3129: fclose(file);
3130: }
3131: }
3132:
3133: //====================
3134:
3135: void WriteBool(LPCSTR fp, LPCSTR keyword, bool value)
3136: {
3137: if (pSettings->writeProtection) return;
3138:
3139: char tmp[50];
3140: if (value) strcpy_s(tmp, sizeofArray(tmp), "true");
3141: else strcpy_s(tmp, sizeofArray(tmp), "false");
3142:
3143: WriteValue(fp, keyword, tmp);
3144: }
3145:
3146: //====================
3147:
3148: void WriteInt(LPCSTR fp, LPCSTR keyword, int value)
3149: {
3150: if (pSettings->writeProtection) return;
3151:
3152: char tmp[50];
3153: sprintf_s(tmp, sizeofArray(tmp), "%d", value);
3154:
3155: WriteValue(fp, keyword, tmp);
3156: }
3157:
3158: //====================
3159:
3160: void WriteString(LPCSTR fp, LPCSTR keyword, LPSTR value)
3161: {
3162: if (pSettings->writeProtection) return;
3163:
3164: WriteValue(fp, keyword, value);
3165: }
3166:
3167: //====================
3168:
3169: void WriteColor(LPCSTR fp, LPCSTR keyword, COLORREF value)
3170: {
3171: if (pSettings->writeProtection) return;
3172:
3173: char tmp[MAX_LINE_LENGTH];
3174: sprintf_s(tmp, sizeofArray(tmp), "#%02x%02x%02x", GetRValue(value), GetGValue(value), GetBValue(value));
3175:
3176: WriteValue(fp, keyword, tmp);
3177: }
3178:
3179: //===========================================================================
3180: // Functions: GetTraySize/GetTrayIcon + GetUnderExplorer
3181: // Purpose: ...
3182: //===========================================================================
3183:
3184: // Note: xoblite bb5 onwards is always running alongside Explorer as an "extending shell" (i.e. rather than being an "alternative" == replacement shell like in the old days).
3185: // The following functions have therefore been kept for basic API compatibility only; the systray itself was removed in xoblite bb5 and hence these functions will "return nothing".
3186: int GetTraySize() { return 0; }
3187: trayIconItem* GetTrayIcon(int pointer) { return NULL; }
3188: bool GetUnderExplorer() { return pSettings->underExplorer; }; // Note: Even in xoblite bb5, we do a check for Explorer at startup for other purposes, so we might just return that boolean here even if typically always "true"...
3189:
3190: //===========================================================================
3191: // Function: GetDesktopInfo
3192: // Purpose: ...
3193: //===========================================================================
3194:
3195: void GetDesktopInfo(DesktopInfo *deskInfo)
3196: {
3197: strncpy(deskInfo->name, pWorkspaces->workspaceNames[pSettings->currentWorkspace].c_str(), 32);
3198: deskInfo->name[31] = 0;
3199: deskInfo->isCurrent = true;
3200: deskInfo->number = pSettings->currentWorkspace;
3201: deskInfo->ScreensX = pSettings->numberOfWorkspaces;
3202: // deskInfo->deskNames is currently not supported
3203: }
3204:
3205: //===========================================================================
3206: // Functions: GetTaskListSize/SetTaskWorkspace/GetTaskWorkspace/
3207: // GetTask/GetActiveTask
3208: // Purpose: ...
3209: //===========================================================================
3210:
3211: int GetTaskListSize()
3212: {
3213: if (pTaskbar) return (int)pTaskbar->taskList.size();
3214: else return 0;
3215: }
3216:
3217: //====================
3218:
3219: void SetTaskWorkspace(HWND hwnd, int workspace)
3220: {
3221: if (pWorkspaces) pWorkspaces->MoveWindowToWorkspace(hwnd, workspace);
3222: }
3223:
3224: //====================
3225:
3226: int GetTaskWorkspace(HWND hwnd)
3227: {
3228: if (pWorkspaces) return pWorkspaces->GetWorkspaceByWindow(hwnd);
3229: else return 0;
3230: }
3231:
3232: //====================
3233:
3234: HWND GetTask(int pointer)
3235: {
3236: if (pTaskbar)
3237: {
3238: if ((pointer >= 0) && (pointer <= (int)pTaskbar->taskList.size()))
3239: {
3240: return pTaskbar->taskList[pointer]->hwnd;
3241: }
3242: }
3243:
3244: return NULL;
3245: }
3246:
3247: //====================
3248:
3249: int GetActiveTask()
3250: {
3251: if (pTaskbar)
3252: {
3253: int index = pTaskbar->GetActiveTask();
3254: if (index != NULL) return index;
3255: }
3256:
3257: return -1;
3258: }
3259:
3260: //===========================================================================
3261: // Function: IsOnTaskbar
3262: // Purpose: Checks if a specific window belongs to a task on the taskbar
3263: // (nb. and in turn leveraging its prior window validation etc)
3264: //===========================================================================
3265:
3266: bool IsOnTaskbar(HWND hwnd)
3267: {
3268: if (pTaskbar)
3269: {
3270: if (pTaskbar->FindTask(hwnd) >= 0) return true;
3271: }
3272:
3273: return false;
3274: }
3275:
3276: //===========================================================================
3277: // Function: IsAppRunning
3278: // Purpose: Check if an application with the specified .exe path is running,
3279: // and if so returns the HWND of the application, otherwise NULL
3280: //===========================================================================
3281:
3282: HWND IsAppRunning(LPSTR path)
3283: {
3284: if (pTaskbar)
3285: {
3286: for (int i=0; i < (int)pTaskbar->taskList.size(); i++)
3287: {
3288: if (!_stricmp(pTaskbar->taskList[i]->path, path)) return pTaskbar->taskList[i]->hwnd;
3289: }
3290: }
3291:
3292: return NULL;
3293: }
3294:
3295: //===========================================================================
3296: // Function: DownloadFile
3297: // Purpose: ...
3298: //===========================================================================
3299:
3300: bool DownloadFile(LPCSTR url, LPCSTR path)
3301: {
3302: // DownloadFile will accept an input string containing multiple URLs
3303: // (using space as the delimiter), in which case it will merge all
3304: // the files together into a single output file! :D
3305:
3306: HANDLE file = NULL;
3307: HINTERNET iopen = NULL, iopenurl = NULL;
3308: bool status = true; // Will be set to false if any of the specified downloads fail
3309:
3310: char remaining[MAX_LINE_LENGTH], token[MAX_LINE_LENGTH], extra[MAX_LINE_LENGTH];
3311: LPSTR tokens[1];
3312: tokens[0] = token;
3313:
3314: strcpy_s(remaining, sizeofArray(remaining), url);
3315:
3316: //====================
3317:
3318: while (strnlen_s(remaining, sizeofArray(remaining)))
3319: {
3320: // Get the next token from the list of URLs...
3321: token[0] = extra[0] = '\0';
3322: BBTokenize (remaining, tokens, 1, extra);
3323: strcpy_s(remaining, sizeofArray(remaining), extra);
3324:
3325: // ...then try fetching the file from the web...
3326: iopen = InternetOpen("xoblite", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);//INTERNET_FLAG_ASYNC);
3327: if (iopen)
3328: {
3329: iopenurl = InternetOpenUrl(iopen, token, NULL, 0, INTERNET_FLAG_RELOAD, 0);
3330: if (iopenurl)
3331: {
3332: // unsigned int size = 0;
3333: // InternetQueryDataAvailable(iopenurl, (LPDWORD)&size, 0, 0);
3334:
3335: char buffer[1024];
3336: DWORD bytesRead = 0, retLength = 0;
3337:
3338: // Create the file if we haven't done so already...
3339: if (!file) file = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3340:
3341: if (file)
3342: {
3343: // Download data in chunks of 1024 bytes...
3344: while (InternetReadFile(iopenurl, (LPVOID)buffer, 1024, &bytesRead))
3345: {
3346: if (bytesRead == 0) break;
3347:
3348: // Stop downloading if the file seems to be 404...
3349: // if (strstr(buffer, "<title>404 Not Found</title>")) break;
3350:
3351: WriteFile(file, buffer, bytesRead, &retLength, NULL);
3352: }
3353:
3354: InternetCloseHandle(iopenurl);
3355: InternetCloseHandle(iopen);
3356: }
3357: else
3358: {
3359: status = false;
3360: InternetCloseHandle(iopenurl);
3361: InternetCloseHandle(iopen);
3362: }
3363: }
3364: else
3365: {
3366: status = false;
3367: InternetCloseHandle(iopen);
3368: }
3369: }
3370: }
3371:
3372: //====================
3373:
3374: // Close the file...
3375: if (file) CloseHandle(file);
3376:
3377: return status;
3378: }
3379:
3380: //===========================================================================
3381: // Function: ParseDropFiles
3382: // Purpose: Common handling of drag'n'drop events for all core UI elements
3383: //===========================================================================
3384:
3385: int ParseDropFiles(HWND hwnd, WPARAM wParam)
3386: {
3387: static TCHAR filename[MAX_LINE_LENGTH];
3388: DragQueryFile((HDROP)wParam, 0, filename, sizeof(filename));
3389:
3390: char path[MAX_LINE_LENGTH];
3391: strncpy(path, filename, MAX_LINE_LENGTH-1);
3392: if (path[0] == '\"') StrRemoveEncap(path);
3393:
3394: //====================
3395:
3396: if (pDesktop)
3397: {
3398: // Relay drag to desktop information to interrested plugins...
3399: if (hwnd == pDesktop->hDesktopWnd) SendMessage(GetBBWnd(), BB_DRAGTODESKTOP, 0, (LPARAM)path);
3400: }
3401:
3402: //====================
3403:
3404: // Make sure the dropped file isn't a directory...
3405: if (PathIsDirectory(filename))
3406: {
3407: DragFinish((HDROP)wParam);
3408: return 0;
3409: }
3410:
3411: //====================
3412:
3413: // We only need to check the last 4 characters to get the extension...
3414: int pointer = strnlen_s(path, sizeofArray(path)) - 4;
3415:
3416: if (! _stricmp(&path[pointer], ".dll"))
3417: {
3418: // Load plugin...
3419: if (pPluginManager) pPluginManager->LoadPlugin(filename);
3420: }
3421: else if (! _stricmp(&path[pointer], ".jpg")
3422: || ! _stricmp(&path[pointer], ".png")
3423: || ! _stricmp(&path[pointer], ".bmp")
3424: || ! _stricmp(&path[pointer], "jpeg"))
3425: {
3426: // If the file is a JPG/JPEG, PNG or BMP we set it as wallpaper...
3427: if (GetAsyncKeyState(VK_CONTROL) & 0x8000) pWallpaper->SetWallpaper(path, "center"); // Is the control key held down? -> center mode
3428: else if (GetAsyncKeyState(VK_MENU) & 0x8000) pWallpaper->SetWallpaper(path, "tile"); // Is the alt key held down? -> tile mode
3429: else if (GetAsyncKeyState(VK_SHIFT) & 0x8000) pWallpaper->SetWallpaper(path, "span"); // Is the shift key held down? -> span mode
3430: else pWallpaper->SetWallpaper(path, "stretch"); // Default -> stretch/full mode
3431: }
3432: else
3433: {
3434: // Look for a line that should "always" exist in a style file...
3435: if (strlen(ReadString(filename, "menu.frame.", "")))
3436: {
3437: // Set new style...
3438: PostMessage(GetBBWnd(), BB_SETSTYLE, 0, (LPARAM)filename);
3439: }
3440: }
3441:
3442: //====================
3443:
3444: DragFinish((HDROP)wParam);
3445:
3446: return 0;
3447: }
3448:
3449: //===========================================================================
3450: // Functions: CopyStringToClipboard/RetrieveStringFromClipboard
3451: // Purpose: ...
3452: //===========================================================================
3453:
3454: bool CopyStringToClipboard(LPSTR string)
3455: {
3456: HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE, strlen(string)+1) ;
3457: if (hGlobal == NULL) return false;
3458:
3459: char* pGlobal = (LPSTR)GlobalLock(hGlobal) ;
3460: if (pGlobal == NULL) return false;
3461:
3462: strcpy(pGlobal, string);
3463: GlobalUnlock (hGlobal);
3464:
3465: if (OpenClipboard(GetBBWnd()))
3466: {
3467: if (EmptyClipboard())
3468: {
3469: if (SetClipboardData(CF_TEXT, hGlobal) != NULL)
3470: {
3471: CloseClipboard();
3472: return true;
3473: }
3474: }
3475:
3476: CloseClipboard();
3477: }
3478:
3479: return false;
3480: }
3481:
3482: //====================
3483:
3484: bool RetrieveStringFromClipboard(LPSTR target)
3485: {
3486: HANDLE handle;
3487:
3488: if (IsClipboardFormatAvailable(CF_TEXT))
3489: {
3490: if (OpenClipboard(GetBBWnd()))
3491: {
3492: handle = GetClipboardData(CF_TEXT);
3493: if (handle != NULL)
3494: {
3495: strncpy(target, (char*)handle, MAX_LINE_LENGTH-1);
3496: CloseClipboard();
3497: return true;
3498: }
3499:
3500: CloseClipboard();
3501: }
3502: }
3503:
3504: strcpy(target, ""); // Failed or nothing was found on the clipboard...
3505:
3506: return false;
3507: }
3508:
3509: //===========================================================================
3510: // Functions: DrawTextWithEffectsEx (input string in Unicode or ANSI) ->
3511: // -> DrawTextWithEffects (ANSI) / DrawTextWithEffectsUnicode
3512: // Purpose: Like a regular DrawText, but with optional shadow/outline... :D
3513: //===========================================================================
3514:
3515: void DrawTextWithEffectsEx(HDC hdc, RECT r, LPWSTR textUnicode, LPSTR textANSI, unsigned int format, COLORREF textColor, bool outline, COLORREF outlineColor, bool shadow, COLORREF shadowColor, int shadowX, int shadowY)
3516: {
3517: if (textUnicode != NULL) DrawTextWithEffectsUnicode(hdc, r, textUnicode, format, textColor, outline, outlineColor, shadow, shadowColor, shadowX, shadowY);
3518: else DrawTextWithEffects(hdc, r, textANSI, format, textColor, outline, outlineColor, shadow, shadowColor, shadowX, shadowY);
3519: }
3520:
3521: //====================
3522:
3523: void DrawTextWithEffects(HDC hdc, RECT r, LPSTR text, unsigned int format, COLORREF textColor, bool outline, COLORREF outlineColor, bool shadow, COLORREF shadowColor, int shadowX, int shadowY)
3524: {
3525: wchar_t textInUnicode[MAX_LINE_LENGTH*10]; // (nb. this much text is typically only remotely happening in e.g. logging popup dialogs, cf. matching size used in PopupDialog.h)
3526: MultiByteToWideChar(CP_ACP, 0, text, strlen(text)+1, textInUnicode, sizeof(textInUnicode)); // We need to use the system default Windows ANSI code page (CP_ACP) for conversion here...
3527: DrawTextWithEffectsUnicode(hdc, r, textInUnicode, format, textColor, outline, outlineColor, shadow, shadowColor, shadowX, shadowY);
3528: }
3529:
3530: //====================
3531:
3532: void DrawTextWithEffectsUnicode(HDC hdc, RECT r, LPWSTR text, unsigned int format, COLORREF textColor, bool outline, COLORREF outlineColor, bool shadow, COLORREF shadowColor, int shadowX, int shadowY)
3533: {
3534: // Note#1: As the text itself should be topmost, below that the outline, and below that the shadow,
3535: // we need to draw it in the opposite order i.e. shadow->outline->text, see below.
3536: // Note#2: Yes, this way is quite compute-intensive, but also the best looking, so... ;)
3537:
3538: RECT s;
3539:
3540: //====================
3541:
3542: if (outline && shadow)
3543: {
3544: CopyRect(&s, &r);
3545: // if (pSettings->doubleScaleHiDPI) OffsetRect(&s, shadowX*2, shadowY*2);
3546: // else OffsetRect(&s, shadowX, shadowY);
3547: if (pSettings->doubleScaleHiDPI && (shadowX==1) && (shadowY==1)) OffsetRect(&s, 2, 2);
3548: else OffsetRect(&s, shadowX, shadowY);
3549: // OffsetRect(&s, shadowX, shadowY);
3550: DrawTextWithEffectsUnicode(hdc, s, text, format, shadowColor, true, shadowColor, false, 0, 0, 0); // Draw [bigger due to the outline] shadow...
3551: DrawTextWithEffectsUnicode(hdc, r, text, format, textColor, true, outlineColor, false, 0, 0, 0); // ...with outline and regular text on top...
3552: }
3553: else if (shadow)
3554: {
3555: // Draw shadow... (1 pixel thick for non-HiDPI, 2 pixels thick for HiDPI,
3556: // with its position adjusted for outlined text if so applicable)
3557:
3558: SetTextColor(hdc, shadowColor);
3559:
3560: if (outline) // -> Outlined text -> Shadow offset positon adjusted accordingly
3561: {
3562: if (pSettings->doubleScaleHiDPI)
3563: {
3564: CopyRect(&s, &r);
3565: OffsetRect(&s, 4, 0);
3566: DrawTextW(hdc, text, wcslen(text), &s, format);
3567: OffsetRect(&s, 0, 1);
3568: DrawTextW(hdc, text, wcslen(text), &s, format);
3569: OffsetRect(&s, 0, 1);
3570: DrawTextW(hdc, text, wcslen(text), &s, format);
3571: OffsetRect(&s, 0, 1);
3572: DrawTextW(hdc, text, wcslen(text), &s, format);
3573: OffsetRect(&s, 0, 1);
3574: DrawTextW(hdc, text, wcslen(text), &s, format);
3575: OffsetRect(&s, -1, 0);
3576: DrawTextW(hdc, text, wcslen(text), &s, format);
3577: OffsetRect(&s, -1, 0);
3578: DrawTextW(hdc, text, wcslen(text), &s, format);
3579: OffsetRect(&s, -1, 0);
3580: DrawTextW(hdc, text, wcslen(text), &s, format);
3581: OffsetRect(&s, -1, 0);
3582: DrawTextW(hdc, text, wcslen(text), &s, format);
3583:
3584: CopyRect(&s, &r);
3585: OffsetRect(&s, 3, -1);
3586: DrawTextW(hdc, text, wcslen(text), &s, format);
3587: OffsetRect(&s, 0, 1);
3588: DrawTextW(hdc, text, wcslen(text), &s, format);
3589: OffsetRect(&s, 0, 1);
3590: DrawTextW(hdc, text, wcslen(text), &s, format);
3591: OffsetRect(&s, 0, 1);
3592: DrawTextW(hdc, text, wcslen(text), &s, format);
3593: OffsetRect(&s, 0, 1);
3594: DrawTextW(hdc, text, wcslen(text), &s, format);
3595: OffsetRect(&s, -1, 0);
3596: DrawTextW(hdc, text, wcslen(text), &s, format);
3597: OffsetRect(&s, -1, 0);
3598: DrawTextW(hdc, text, wcslen(text), &s, format);
3599: OffsetRect(&s, -1, 0);
3600: DrawTextW(hdc, text, wcslen(text), &s, format);
3601: OffsetRect(&s, -1, 0);
3602: DrawTextW(hdc, text, wcslen(text), &s, format);
3603: }
3604: else
3605: {
3606: CopyRect(&s, &r);
3607: OffsetRect(&s, 2, 0);
3608: DrawTextW(hdc, text, wcslen(text), &s, format);
3609: OffsetRect(&s, 0, 1);
3610: DrawTextW(hdc, text, wcslen(text), &s, format);
3611: OffsetRect(&s, 0, 1);
3612: DrawTextW(hdc, text, wcslen(text), &s, format);
3613: OffsetRect(&s, -1, 0);
3614: DrawTextW(hdc, text, wcslen(text), &s, format);
3615: OffsetRect(&s, -1, 0);
3616: DrawTextW(hdc, text, wcslen(text), &s, format);
3617: }
3618: }
3619: else // -> Non-outlined text -> Shadow offset position as per the input parameters
3620: {
3621: CopyRect(&s, &r);
3622: //// OffsetRect(&s, 2, 2);
3623: // if (pSettings->doubleScaleHiDPI) OffsetRect(&s, shadowX*2, shadowY*2);
3624: // else OffsetRect(&s, shadowX, shadowY);
3625: OffsetRect(&s, shadowX, shadowY);
3626: DrawTextW(hdc, text, wcslen(text), &s, format);
3627: }
3628: }
3629:
3630: //====================
3631:
3632: if (outline)
3633: {
3634: // Draw outline... (1 pixel thick for non-HiDPI, 2 pixels thick for HiDPI)
3635:
3636: SetTextColor(hdc, outlineColor);
3637:
3638: if (pSettings->doubleScaleHiDPI)
3639: {
3640: CopyRect(&s, &r);
3641: OffsetRect(&s, 0, -2);
3642: DrawTextW(hdc, text, wcslen(text), &s, format);
3643: OffsetRect(&s, 1, 0);
3644: DrawTextW(hdc, text, wcslen(text), &s, format);
3645: OffsetRect(&s, 1, 0);
3646: DrawTextW(hdc, text, wcslen(text), &s, format);
3647: OffsetRect(&s, 0, 1);
3648: DrawTextW(hdc, text, wcslen(text), &s, format);
3649: OffsetRect(&s, 0, 1);
3650: DrawTextW(hdc, text, wcslen(text), &s, format);
3651: OffsetRect(&s, 0, 1);
3652: DrawTextW(hdc, text, wcslen(text), &s, format);
3653: OffsetRect(&s, 0, 1);
3654: DrawTextW(hdc, text, wcslen(text), &s, format);
3655: OffsetRect(&s, -1, 0);
3656: DrawTextW(hdc, text, wcslen(text), &s, format);
3657: OffsetRect(&s, -1, 0);
3658: DrawTextW(hdc, text, wcslen(text), &s, format);
3659: OffsetRect(&s, -1, 0);
3660: DrawTextW(hdc, text, wcslen(text), &s, format);
3661: OffsetRect(&s, -1, 0);
3662: DrawTextW(hdc, text, wcslen(text), &s, format);
3663: OffsetRect(&s, 0, -1);
3664: DrawTextW(hdc, text, wcslen(text), &s, format);
3665: OffsetRect(&s, 0, -1);
3666: DrawTextW(hdc, text, wcslen(text), &s, format);
3667: OffsetRect(&s, 0, -1);
3668: DrawTextW(hdc, text, wcslen(text), &s, format);
3669: OffsetRect(&s, 0, -1);
3670: DrawTextW(hdc, text, wcslen(text), &s, format);
3671: OffsetRect(&s, 1, 0);
3672: DrawTextW(hdc, text, wcslen(text), &s, format);
3673: }
3674:
3675: CopyRect(&s, &r);
3676: OffsetRect(&s, 0, -1);
3677: DrawTextW(hdc, text, wcslen(text), &s, format);
3678: OffsetRect(&s, 1, 0);
3679: DrawTextW(hdc, text, wcslen(text), &s, format);
3680: OffsetRect(&s, 0, 1);
3681: DrawTextW(hdc, text, wcslen(text), &s, format);
3682: OffsetRect(&s, 0, 1);
3683: DrawTextW(hdc, text, wcslen(text), &s, format);
3684: OffsetRect(&s, -1, 0);
3685: DrawTextW(hdc, text, wcslen(text), &s, format);
3686: OffsetRect(&s, -1, 0);
3687: DrawTextW(hdc, text, wcslen(text), &s, format);
3688: OffsetRect(&s, 0, -1);
3689: DrawTextW(hdc, text, wcslen(text), &s, format);
3690: OffsetRect(&s, 0, -1);
3691: DrawTextW(hdc, text, wcslen(text), &s, format);
3692: }
3693:
3694: //====================
3695:
3696: // Draw text...
3697: SetTextColor(hdc, textColor);
3698: DrawTextW(hdc, text, wcslen(text), &r, format);
3699: }
3700:
3701: //====================
3702:
3703: bool DrawTextEvolved(HDC hdc, RECT* rect, LPSTR styleElement, LPWSTR textUnicode, LPSTR textANSI, unsigned int fontHeightOverride, unsigned int format, bool getSize)
3704: {
3705: StyleItem* element = FindStyleElement(styleElement);
3706:
3707: if (element != NULL) // -> Supported style element found!
3708: {
3709: unsigned int fontHeight;
3710: if (fontHeightOverride > 0) fontHeight = fontHeightOverride;
3711: else fontHeight = element->FontHeight;
3712:
3713: if (getSize) // -> Find out the necessary size RECT to draw the text... (i.e. element-aware GetTextExtentPoint32 wrapper)
3714: {
3715: SIZE size;
3716: HDC fonthdc = CreateDC("DISPLAY", NULL, NULL, NULL);
3717: HFONT font = CreateFont(fontHeight, 0, 0, 0, element->FontWeight, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, element->Font);
3718: HGDIOBJ oldfont = SelectObject(fonthdc, font);
3719:
3720: if (textUnicode != NULL) GetTextExtentPoint32W(fonthdc, textUnicode, wcslen(textUnicode), &size);
3721: else GetTextExtentPoint32(fonthdc, textANSI, strlen(textANSI), &size);
3722:
3723: if (element->FontOutline) size.cx += 2;
3724: else if (element->FontShadow) size.cx += 1;
3725: size.cx += (element->marginWidth * 2) + (element->borderWidth * 2);
3726: size.cy += (element->marginWidth * 2) + (element->borderWidth * 2);
3727:
3728: SetRect(rect, 0, 0, size.cx, size.cy);
3729:
3730: DeleteObject(SelectObject(fonthdc, oldfont));
3731: DeleteDC(fonthdc);
3732:
3733: return true;
3734: }
3735: else // -> Draw the text...
3736: {
3737: unsigned int textFormat = format;
3738: if (format == NULL) textFormat = element->Justify | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS;
3739: HFONT font = CreateFont(fontHeight, 0, 0, 0, element->FontWeight, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, element->Font);
3740: HGDIOBJ oldfont = SelectObject(hdc, font);
3741: SetBkMode(hdc, TRANSPARENT);
3742: if (textUnicode != NULL) DrawTextWithEffectsUnicode(hdc, *rect, textUnicode, textFormat, element->TextColor, element->FontOutline, element->OutlineColor, element->FontShadow, element->ShadowColor, element->ShadowX, element->ShadowY);
3743: else DrawTextWithEffects(hdc, *rect, textANSI, textFormat, element->TextColor, element->FontOutline, element->OutlineColor, element->FontShadow, element->ShadowColor, element->ShadowX, element->ShadowY);
3744: DeleteObject(SelectObject(hdc, oldfont));
3745: return true;
3746: }
3747: }
3748: else return false; // -> Unsupported style element, nothing drawn...
3749: }
3750: /*
3751: bool DrawTextEvolved(HDC hdc, RECT* rect, LPSTR styleElement, LPSTR text, unsigned int fontHeightOverride, unsigned int format, bool getSize)
3752: {
3753: return DrawTextEvolvedEx(hdc, rect, styleElement, NULL, text, fontHeightOverride, format, getSize);
3754: }
3755: */
3756: //===========================================================================
3757: // Function: DrawSatHueIcon
3758: // Purpose: Like a regular DrawIconEx, but with optional sat/hue... ;)
3759: //===========================================================================
3760:
3761: // Note: The saturation/hue code section in DrawSatHueIcon is a heavily modified
3762: // version of the equivalent section in LiteStep's systray2 module (systray.cpp),
3763: // which is copyright (C) 1997-2002 The LiteStep Development Team.
3764:
3765: BYTE red, green, blue, greyscale, destred, destgreen, destblue;
3766: COLORREF pixel;
3767: int invsat, invhue;
3768:
3769: void DrawSatHueIcon(HDC hdc, RECT r, HICON icon, int size, int saturation, int hue)
3770: {
3771: // Should we apply saturation or hue?
3772: if (saturation < 255 || hue > 0)
3773: {
3774: HDC iconhdc = CreateCompatibleDC(hdc);
3775: HBITMAP iconbufbmp = ::CreateCompatibleBitmap(hdc, size, size*2);
3776: HBITMAP oldiconbuf = (HBITMAP) ::SelectObject(iconhdc, iconbufbmp);
3777:
3778: // An icon drawn using DI_NORMAL doesn't always seem to be masked properly,
3779: // so we perform the masking manually by drawing the icon and mask side-by-side
3780: // into a temporary buffer, applying saturation and hue to the icon's non-masked
3781: // pixels, and copying them into the destination HDC...
3782: DrawIconEx(iconhdc, 0, 0, icon, size, size, 0, NULL, DI_MASK);
3783: DrawIconEx(iconhdc, 0, size, icon, size, size, 0, NULL, DI_NORMAL);
3784:
3785: invsat = 255 - saturation;
3786: invhue = 255 - hue;
3787:
3788: for (int y=0; y < size; y++)
3789: {
3790: for (int x=0; x < size; x++)
3791: {
3792: // Check if the mask pixel is a transparent pixel...
3793: // if (!GetPixel(iconhdc, x, y))
3794: if (GetPixel(iconhdc, x, y) == 0x000000)
3795: {
3796: // If not, we read the icon pixel color...
3797: pixel = GetPixel(iconhdc, (x), (size+y));
3798: red = GetRValue(pixel);
3799: green = GetGValue(pixel);
3800: blue = GetBValue(pixel);
3801:
3802: // ...apply saturation...
3803: if (saturation < 255)
3804: {
3805: greyscale = (BYTE)(red*0.3086 + green*0.6094 + blue*0.0820);
3806: red = (BYTE)((red*saturation + greyscale*invsat + 255)>>8);
3807: green = (BYTE)((green*saturation + greyscale*invsat + 255)>>8);
3808: blue = (BYTE)((blue*saturation + greyscale*invsat + 255)>>8);
3809: }
3810: // ...and hue...
3811: if (hue > 0)
3812: {
3813: // ...based on the colour of the destination pixel (i.e. the background)...
3814: pixel = GetPixel(hdc, (r.left + x), (r.top + y));
3815: destred = GetRValue(pixel);
3816: destgreen = GetGValue(pixel);
3817: destblue = GetBValue(pixel);
3818:
3819: // ...and the hue intensity...
3820: red = (BYTE)((red*invhue + destred*hue + 255)>>8);
3821: green = (BYTE)((green*invhue + destgreen*hue + 255)>>8);
3822: blue = (BYTE)((blue*invhue + destblue*hue + 255)>>8);
3823: }
3824: // ...and finally we copy the sat'n'hue icon pixel to the destination...
3825: SetPixel(hdc, (r.left + x), (r.top + y), RGB(red, green, blue));
3826: }
3827: // else if (pSettings->debugLogging && saturation==0 && hue==255) SetPixel(hdc, (r.left + x), (r.top + y), 0xff00ff);
3828: }
3829: }
3830:
3831: SelectObject(iconhdc, oldiconbuf);
3832: DeleteObject(iconbufbmp);
3833: DeleteDC(iconhdc);
3834: }
3835: else
3836: {
3837: // No saturation or hue modifications, just draw the icon...
3838: DrawIconEx(hdc, r.left, r.top, icon, size, size, 0, NULL, DI_NORMAL);
3839: }
3840: }
3841:
3842: //===========================================================================
3843: // Function: DrawGlyph
3844: // Purpose: ...
3845: //===========================================================================
3846:
3847: void DrawGlyph(HDC hdc, RECT r, int glyph, COLORREF glyphColor)
3848: {
3849: pBImage->DrawGlyph(hdc, r, glyph, glyphColor);
3850: }
3851:
3852: //===========================================================================
3853: // Function: GetParentFolder
3854: // Purpose: ...
3855: //===========================================================================
3856:
3857: int GetParentFolder(LPSTR path)
3858: {
3859: int nLen = strlen(path) - 1;
3860: if (path[nLen] == '\\') nLen--; // Looking for the parent folder of a folder?
3861:
3862: // Extract the parent folder from the specified path...
3863: while (nLen > 0 && path[nLen] != '\\') nLen--;
3864: path[nLen+1] = 0;
3865:
3866: return nLen+1; // Return the position of the file name following the folder path...
3867: }
3868:
3869: //===========================================================================
3870: //===========================================================================
3871: //===========================================================================
3872:
3873: // Note: The following simplified function was included purely for basic compatibility with the
3874: // bb(C)Lean(Mod)(Zero) modified BBApi, to be able to load e.g. the bbinterfaceMod_iTunes plugin...
3875: HMONITOR GetMonitorRect(void* from, RECT* r, int Flags)
3876: {
3877: return MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
3878: }
3879:
3880: //===========================================================================
3881: