reactos/dll/cpl/console/console.c
Hermès Bélusca-Maïto c4e2826c73
[CONSOLE][CONCFG][CONSRV] Provide support for specified additional TrueType fonts + bugfixes.
CORE-12451 CORE-13182 CORE-13196

- CONSOLE: Initialize the additional TrueType fonts cache.
  * Fix the font preview when a TrueType font has been selected.
  * Refresh the available fonts and the font preview when the selected
    code page is changed (Work In Progress), or when the OS pool of
    font resources has changed (WM_FONTCHANGE message).

- CONCFG: Implement support for the additional TrueType fonts cache:
  the contents of the cache is enumerated under the registry key
    HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont

  * Add helper functions and macros.
  * In CreateConsoleFontEx(), set the mandatory font pitch&family flags
    and remove those that we do not support.
  * In IsValidConsoleFont2(), update the validity checks and the
    documentation links.

- CONSRV: Load/refresh the additional TrueType fonts cache when needed.
2019-05-19 23:10:41 +02:00

388 lines
11 KiB
C

/*
* PROJECT: ReactOS Console Configuration DLL
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/cpl/console/console.c
* PURPOSE: Initialization
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
#include "console.h"
#define NDEBUG
#include <debug.h>
INT_PTR CALLBACK OptionsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK FontProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK LayoutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK ColorsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
HINSTANCE hApplet = NULL;
/* Local copy of the console information */
PCONSOLE_STATE_INFO ConInfo = NULL;
/* What to do with the console information */
static BOOL SetConsoleInfo = FALSE;
static BOOL SaveConsoleInfo = FALSE;
static VOID
InitPropSheetPage(PROPSHEETPAGEW *psp,
WORD idDlg,
DLGPROC DlgProc)
{
ZeroMemory(psp, sizeof(*psp));
psp->dwSize = sizeof(*psp);
psp->dwFlags = PSP_DEFAULT;
psp->hInstance = hApplet;
psp->pszTemplate = MAKEINTRESOURCEW(idDlg);
psp->pfnDlgProc = DlgProc;
psp->lParam = 0;
}
static VOID
InitDefaultConsoleInfo(PCONSOLE_STATE_INFO pConInfo)
{
// FIXME: Also retrieve the value of REG_DWORD CurrentPage.
ConCfgGetDefaultSettings(pConInfo);
}
static INT_PTR
CALLBACK
ApplyProc(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (uMsg)
{
case WM_INITDIALOG:
{
CheckDlgButton(hwndDlg, IDC_RADIO_APPLY_CURRENT, BST_CHECKED);
return TRUE;
}
case WM_COMMAND:
{
if (LOWORD(wParam) == IDOK)
{
if (IsDlgButtonChecked(hwndDlg, IDC_RADIO_APPLY_CURRENT) == BST_CHECKED)
EndDialog(hwndDlg, IDC_RADIO_APPLY_CURRENT);
else
EndDialog(hwndDlg, IDC_RADIO_APPLY_ALL);
}
else if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hwndDlg, IDCANCEL);
}
break;
}
default:
break;
}
return FALSE;
}
VOID
ApplyConsoleInfo(HWND hwndDlg)
{
static BOOL ConsoleInfoAlreadySaved = FALSE;
/*
* We already applied all the console properties (and saved if needed).
* Nothing more needs to be done.
*/
if (ConsoleInfoAlreadySaved)
goto Done;
/*
* If we are setting the default parameters, just save them,
* otherwise display the confirmation & apply dialog.
*/
if (ConInfo->hWnd == NULL)
{
SetConsoleInfo = FALSE;
SaveConsoleInfo = TRUE;
}
else
{
INT_PTR res = DialogBoxW(hApplet, MAKEINTRESOURCEW(IDD_APPLYOPTIONS), hwndDlg, ApplyProc);
SetConsoleInfo = (res != IDCANCEL);
SaveConsoleInfo = (res == IDC_RADIO_APPLY_ALL);
if (SetConsoleInfo == FALSE)
{
/* Don't destroy when the user presses cancel */
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
return;
}
}
/*
* We applied all the console properties (and saved if needed).
* Set the flag so that if this function is called again, we won't
* need to redo everything again.
*/
ConsoleInfoAlreadySaved = TRUE;
Done:
/* Options have been applied */
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
return;
}
static int CALLBACK
PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
{
// NOTE: This callback is needed to set large icon correctly.
HICON hIcon;
switch (uMsg)
{
case PSCB_INITIALIZED:
{
hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_CPLICON));
SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
break;
}
}
return 0;
}
/* First Applet */
static LONG
APIENTRY
InitApplet(HANDLE hSectionOrWnd)
{
INT_PTR Result;
PCONSOLE_STATE_INFO pSharedInfo = NULL;
WCHAR szTitle[MAX_PATH + 1];
PROPSHEETPAGEW psp[4];
PROPSHEETHEADERW psh;
INT i = 0;
/*
* Because of Windows compatibility, we need to behave the same concerning
* information sharing with CONSRV. For some obscure reason the designers
* decided to use the CPlApplet hWnd parameter as being either a handle to
* the applet's parent caller's window (in case we ask for displaying
* the global console settings), or a handle to a shared section holding
* a CONSOLE_STATE_INFO structure (they don't use the extra l/wParams).
*/
/*
* Try to open the shared section via the handle parameter. If we succeed,
* it means we were called by CONSRV for retrieving/setting parameters for
* a given console. If we fail, it means we are retrieving/setting default
* global parameters (and we were either called by CONSRV or directly by
* the user via the Control Panel, etc...)
*/
pSharedInfo = MapViewOfFile(hSectionOrWnd, FILE_MAP_READ, 0, 0, 0);
if (pSharedInfo != NULL)
{
/*
* We succeeded. We were called by CONSRV and are retrieving
* parameters for a given console.
*/
/* Copy the shared data into our allocated buffer */
DPRINT1("pSharedInfo->cbSize == %lu ; sizeof(CONSOLE_STATE_INFO) == %u\n",
pSharedInfo->cbSize, sizeof(CONSOLE_STATE_INFO));
ASSERT(pSharedInfo->cbSize >= sizeof(CONSOLE_STATE_INFO));
/* Allocate a local buffer to hold console information */
ConInfo = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
pSharedInfo->cbSize);
if (ConInfo)
RtlCopyMemory(ConInfo, pSharedInfo, pSharedInfo->cbSize);
/* Close the section */
UnmapViewOfFile(pSharedInfo);
CloseHandle(hSectionOrWnd);
if (!ConInfo) return 0;
}
else
{
/*
* We failed. We are retrieving the default global parameters.
*/
/* Allocate a local buffer to hold console information */
ConInfo = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(CONSOLE_STATE_INFO));
if (!ConInfo) return 0;
/*
* Setting the console window handle to NULL indicates we are
* retrieving/setting the default console parameters.
*/
ConInfo->hWnd = NULL;
ConInfo->ConsoleTitle[0] = UNICODE_NULL;
/* Use defaults */
InitDefaultConsoleInfo(ConInfo);
}
/* Initialize the font support -- additional TrueType fonts cache and current preview font */
InitTTFontCache();
RefreshFontPreview(&FontPreview, ConInfo);
/* Initialize the property sheet structure */
ZeroMemory(&psh, sizeof(psh));
psh.dwSize = sizeof(psh);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | /* PSH_USEHICON | */ PSH_USEICONID | PSH_NOAPPLYNOW | PSH_USECALLBACK;
if (ConInfo->ConsoleTitle[0] != UNICODE_NULL)
StringCchPrintfW(szTitle, ARRAYSIZE(szTitle), L"\"%s\"", ConInfo->ConsoleTitle);
else
StringCchCopyW(szTitle, ARRAYSIZE(szTitle), L"ReactOS Console");
psh.pszCaption = szTitle;
if (pSharedInfo != NULL)
{
/* We were started from a console window: this is our parent (or ConInfo->hWnd is NULL) */
psh.hwndParent = ConInfo->hWnd;
}
else
{
/* We were started in another way (--> default parameters). Caller's window is our parent. */
psh.hwndParent = (HWND)hSectionOrWnd;
}
psh.hInstance = hApplet;
// psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCEW(IDC_CPLICON));
psh.pszIcon = MAKEINTRESOURCEW(IDC_CPLICON);
psh.nPages = ARRAYSIZE(psp);
psh.nStartPage = 0;
psh.ppsp = psp;
psh.pfnCallback = PropSheetProc;
InitPropSheetPage(&psp[i++], IDD_PROPPAGEOPTIONS, OptionsProc);
InitPropSheetPage(&psp[i++], IDD_PROPPAGEFONT , FontProc );
InitPropSheetPage(&psp[i++], IDD_PROPPAGELAYOUT , LayoutProc );
InitPropSheetPage(&psp[i++], IDD_PROPPAGECOLORS , ColorsProc );
/* Display the property sheet */
RegisterWinPrevClass(hApplet);
Result = PropertySheetW(&psh);
UnRegisterWinPrevClass(hApplet);
/* Clear the font support */
ResetFontPreview(&FontPreview);
ClearTTFontCache();
/* Save the console settings */
if (SetConsoleInfo)
{
HANDLE hSection;
/*
* Create a memory section to share with CONSRV, and map it.
*/
hSection = CreateFileMappingW(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
ConInfo->cbSize,
NULL);
if (!hSection)
{
DPRINT1("Error when creating file mapping, error = %d\n", GetLastError());
goto Quit;
}
pSharedInfo = MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (!pSharedInfo)
{
DPRINT1("Error when mapping view of file, error = %d\n", GetLastError());
CloseHandle(hSection);
goto Quit;
}
/* Copy the console information into the section */
RtlCopyMemory(pSharedInfo, ConInfo, ConInfo->cbSize);
/* Unmap it */
UnmapViewOfFile(pSharedInfo);
/* Signal to CONSRV that it can apply the new configuration */
SendMessageW(ConInfo->hWnd, WM_SETCONSOLEINFO, (WPARAM)hSection, 0);
/* Close the section and return */
CloseHandle(hSection);
}
if (SaveConsoleInfo)
{
/* Default settings saved when ConInfo->hWnd == NULL */
ConCfgWriteUserSettings(ConInfo, ConInfo->hWnd == NULL);
}
Quit:
/* Cleanup */
HeapFree(GetProcessHeap(), 0, ConInfo);
ConInfo = NULL;
return (Result != -1);
}
/* Control Panel Callback */
LONG
CALLBACK
CPlApplet(HWND hwndCPl,
UINT uMsg,
LPARAM lParam1,
LPARAM lParam2)
{
switch (uMsg)
{
case CPL_INIT:
return TRUE;
case CPL_EXIT:
// TODO: Free allocated memory
break;
case CPL_GETCOUNT:
return 1;
case CPL_INQUIRE:
{
CPLINFO *CPlInfo = (CPLINFO*)lParam2;
CPlInfo->idIcon = IDC_CPLICON;
CPlInfo->idName = IDS_CPLNAME;
CPlInfo->idInfo = IDS_CPLDESCRIPTION;
break;
}
case CPL_DBLCLK:
InitApplet((HANDLE)hwndCPl);
break;
}
return FALSE;
}
INT
WINAPI
DllMain(HINSTANCE hinstDLL,
DWORD dwReason,
LPVOID lpvReserved)
{
UNREFERENCED_PARAMETER(lpvReserved);
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
hApplet = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
break;
}
return TRUE;
}