1 /* 2 * PROJECT: ReactOS Console Configuration DLL 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/cpl/console/font.c 5 * PURPOSE: Font dialog 6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) 7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 8 */ 9 10 #include "console.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 16 // 17 // Some temporary code for future reference... 18 // 19 #if 0 20 /* 21 * This code comes from PuTTY 22 */ 23 { 24 CHOOSEFONT cf; 25 LOGFONT lf; 26 HDC hdc; 27 FontSpec *fs = (FontSpec *)c->data; 28 29 hdc = GetDC(0); 30 lf.lfHeight = -MulDiv(fs->height, 31 GetDeviceCaps(hdc, LOGPIXELSY), 72); 32 ReleaseDC(0, hdc); 33 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0; 34 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0; 35 lf.lfWeight = (fs->isbold ? FW_BOLD : 0); 36 lf.lfCharSet = fs->charset; 37 lf.lfOutPrecision = OUT_DEFAULT_PRECIS; 38 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 39 lf.lfQuality = DEFAULT_QUALITY; 40 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; 41 strncpy(lf.lfFaceName, fs->name, 42 sizeof(lf.lfFaceName) - 1); 43 lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0'; 44 45 cf.lStructSize = sizeof(cf); 46 cf.hwndOwner = dp->hwnd; 47 cf.lpLogFont = &lf; 48 cf.Flags = (dp->fixed_pitch_fonts ? CF_FIXEDPITCHONLY : 0) | 49 CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; 50 51 if (ChooseFont(&cf)) { 52 fs = fontspec_new(lf.lfFaceName, (lf.lfWeight == FW_BOLD), 53 cf.iPointSize / 10, lf.lfCharSet); 54 dlg_fontsel_set(ctrl, dp, fs); 55 fontspec_free(fs); 56 57 ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); 58 } 59 } 60 61 /* 62 * This code is from consrv. 63 */ 64 { 65 if (!GetTextMetricsW(drawItem->hDC, &Metrics)) 66 { 67 DPRINT1("PaintText: GetTextMetrics failed\n"); 68 SelectObject(drawItem->hDC, OldFont); 69 DeleteObject(Font); 70 return; 71 } 72 GuiData->CharWidth = Metrics.tmMaxCharWidth; 73 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading; 74 75 /* Measure real char width more precisely if possible */ 76 if (GetTextExtentPoint32W(drawItem->hDC, L"R", 1, &CharSize)) 77 GuiData->CharWidth = CharSize.cx; 78 } 79 80 /* 81 * See also: Display_SetTypeFace in applications/fontview/display.c 82 */ 83 #endif 84 85 86 /* 87 * Font pixel heights for TrueType fonts 88 */ 89 static SHORT TrueTypePoints[] = 90 { 91 // 8, 9, 10, 11, 12, 14, 16, 18, 20, 92 // 22, 24, 26, 28, 36, 48, 72 93 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 24, 28, 36, 72 94 }; 95 96 static BOOL CALLBACK 97 EnumFontNamesProc(PLOGFONTW lplf, 98 PNEWTEXTMETRICW lpntm, 99 DWORD FontType, 100 LPARAM lParam) 101 { 102 HWND hwndCombo = (HWND)lParam; 103 LPWSTR pszName = lplf->lfFaceName; 104 105 /* Record the font's attributes (Fixedwidth and Truetype) */ 106 // BOOL fFixed = ((lplf->lfPitchAndFamily & 0x03) == FIXED_PITCH); 107 // BOOL fTrueType = (lplf->lfOutPrecision == OUT_STROKE_PRECIS); 108 109 /* 110 * According to: http://support.microsoft.com/kb/247815 111 * the criteria for console-eligible fonts are: 112 * - The font must be a fixed-pitch font. 113 * - The font cannot be an italic font. 114 * - The font cannot have a negative A or C space. 115 * - If it is a TrueType font, it must be FF_MODERN. 116 * - If it is not a TrueType font, it must be OEM_CHARSET. 117 * 118 * Non documented: vertical fonts are forbidden (their name start with a '@'). 119 * 120 * Additional criteria for Asian installations: 121 * - If it is not a TrueType font, the face name must be "Terminal". 122 * - If it is an Asian TrueType font, it must also be an Asian character set. 123 * 124 * To install additional TrueType fonts to be available for the console, 125 * add entries of type REG_SZ named "0", "00" etc... in: 126 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont 127 * The names of the fonts listed there should match those in: 128 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts 129 */ 130 131 /* 132 * In ReactOS, we relax some criteria: 133 * - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts 134 * that can be italic and have negative A or C space. 135 * - If it is not a TrueType font, it can be from another character set 136 * than OEM_CHARSET. 137 * - We do not support Asian criteria at the moment. 138 * - We do not look into the magic registry key mentioned above. 139 */ 140 141 /* Reject variable width fonts */ 142 if (((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH) 143 #if 0 /* Reject italic and TrueType fonts with negative A or C space */ 144 || (lplf->lfItalic) 145 || !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) 146 #endif 147 ) 148 { 149 DPRINT1("Font '%S' rejected because it%s (lfPitchAndFamily = %d).\n", 150 pszName, !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" : " is broken"), 151 lplf->lfPitchAndFamily); 152 return TRUE; 153 } 154 155 /* Reject TrueType fonts that are not FF_MODERN */ 156 if ((FontType == TRUETYPE_FONTTYPE) && ((lplf->lfPitchAndFamily & 0xF0) != FF_MODERN)) 157 { 158 DPRINT1("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n", 159 pszName, lplf->lfPitchAndFamily); 160 return TRUE; 161 } 162 163 /* Reject non-TrueType fonts that are not OEM */ 164 #if 0 165 if ((FontType != TRUETYPE_FONTTYPE) && (lplf->lfCharSet != OEM_CHARSET)) 166 { 167 DPRINT1("Non-TrueType font '%S' rejected because it's not OEM_CHARSET %d\n", 168 pszName, lplf->lfCharSet); 169 return TRUE; 170 } 171 #else // Improved criterium 172 if ((FontType != TRUETYPE_FONTTYPE) && 173 ((lplf->lfCharSet != ANSI_CHARSET) && (lplf->lfCharSet != DEFAULT_CHARSET) && (lplf->lfCharSet != OEM_CHARSET))) 174 { 175 DPRINT1("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n", 176 pszName, lplf->lfCharSet); 177 return TRUE; 178 } 179 #endif 180 181 /* Reject fonts that are vertical (tategaki) */ 182 if (pszName[0] == L'@') 183 { 184 DPRINT1("Font '%S' rejected because it's vertical\n", pszName); 185 return TRUE; 186 } 187 188 #if 0 // For Asian installations only 189 /* Reject non-TrueType fonts that are not Terminal */ 190 if ((FontType != TRUETYPE_FONTTYPE) && (wcscmp(pszName, L"Terminal") != 0)) 191 { 192 DPRINT1("Non-TrueType font '%S' rejected because it's not Terminal\n", pszName); 193 return TRUE; 194 } 195 196 // TODO: Asian TrueType font must also be an Asian character set. 197 #endif 198 199 /* Make sure the font doesn't already exist in the list */ 200 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)pszName) == LB_ERR) 201 { 202 /* Add the font */ 203 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)pszName); 204 205 DPRINT1("Add font '%S' (lfPitchAndFamily = %d)\n", pszName, lplf->lfPitchAndFamily); 206 207 /* Store this information in the list-item's userdata area */ 208 // SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(fFixed, fTrueType)); 209 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, (WPARAM)FontType); 210 } 211 212 return TRUE; 213 } 214 215 static BOOL CALLBACK 216 EnumFontSizesProc(PLOGFONTW lplf, 217 PNEWTEXTMETRICW lpntm, 218 DWORD FontType, 219 LPARAM lParam) 220 { 221 HWND hwndCombo = (HWND)lParam; 222 WCHAR FontSize[100]; 223 224 if (FontType != TRUETYPE_FONTTYPE) 225 { 226 // int logsize = lpntm->tmHeight - lpntm->tmInternalLeading; 227 // LONG pointsize = MulDiv(logsize, 72, GetDeviceCaps(hdc, LOGPIXELSY)); 228 229 // swprintf(FontSize, L"%2d (%d x %d)", pointsize, lplf->lfWidth, lplf->lfHeight); 230 swprintf(FontSize, L"%d x %d", lplf->lfWidth, lplf->lfHeight); 231 232 /* Make sure the size doesn't already exist in the list */ 233 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR) 234 { 235 /* Add the size */ 236 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize); 237 238 /* 239 * Store this information in the list-item's userdata area. 240 * Format: 241 * Width = FontSize.X = LOWORD(FontSize); 242 * Height = FontSize.Y = HIWORD(FontSize); 243 */ 244 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(lplf->lfWidth, lplf->lfHeight)); 245 } 246 247 return TRUE; 248 } 249 else 250 { 251 ULONG i; 252 for (i = 0; i < ARRAYSIZE(TrueTypePoints); ++i) 253 { 254 swprintf(FontSize, L"%2d", TrueTypePoints[i]); 255 256 /* Make sure the size doesn't already exist in the list */ 257 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR) 258 { 259 /* Add the size */ 260 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize); 261 262 /* 263 * Store this information in the list-item's userdata area. 264 * Format: 265 * Width = FontSize.X = LOWORD(FontSize); 266 * Height = FontSize.Y = HIWORD(FontSize); 267 */ 268 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(0, TrueTypePoints[i])); 269 } 270 } 271 272 return FALSE; 273 } 274 } 275 276 277 static VOID 278 FontSizeChange(HWND hwndDlg, 279 PCONSOLE_STATE_INFO pConInfo); 280 281 static VOID 282 FontTypeChange(HWND hwndDlg, 283 PCONSOLE_STATE_INFO pConInfo) 284 { 285 INT Length, nSel; 286 LPWSTR FaceName; 287 288 HDC hDC; 289 LOGFONTW lf; 290 291 nSel = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, 292 LB_GETCURSEL, 0, 0); 293 if (nSel == LB_ERR) return; 294 295 Length = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, 296 LB_GETTEXTLEN, nSel, 0); 297 if (Length == LB_ERR) return; 298 299 FaceName = HeapAlloc(GetProcessHeap(), 300 HEAP_ZERO_MEMORY, 301 (Length + 1) * sizeof(WCHAR)); 302 if (FaceName == NULL) return; 303 304 Length = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, 305 LB_GETTEXT, nSel, (LPARAM)FaceName); 306 FaceName[Length] = '\0'; 307 308 Length = min(Length/*wcslen(FaceName) + 1*/, LF_FACESIZE - 1); // wcsnlen 309 wcsncpy(pConInfo->FaceName, FaceName, LF_FACESIZE); 310 pConInfo->FaceName[Length] = L'\0'; 311 DPRINT1("pConInfo->FaceName = '%S'\n", pConInfo->FaceName); 312 313 /* Enumerate the available sizes for the selected font */ 314 ZeroMemory(&lf, sizeof(lf)); 315 lf.lfCharSet = DEFAULT_CHARSET; // OEM_CHARSET; 316 // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; 317 wcsncpy(lf.lfFaceName, FaceName, LF_FACESIZE); 318 lf.lfFaceName[Length] = L'\0'; 319 320 hDC = GetDC(NULL); 321 EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontSizesProc, 322 (LPARAM)GetDlgItem(hwndDlg, IDC_LBOX_FONTSIZE), 0); 323 ReleaseDC(NULL, hDC); 324 325 HeapFree(GetProcessHeap(), 0, FaceName); 326 327 // TODO: Select a default font size???? 328 FontSizeChange(hwndDlg, pConInfo); 329 330 // InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE); 331 // InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE); 332 } 333 334 static VOID 335 FontSizeChange(HWND hwndDlg, 336 PCONSOLE_STATE_INFO pConInfo) 337 { 338 INT nSel; 339 ULONG FontSize; 340 WCHAR FontSizeStr[20]; 341 342 nSel = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTSIZE, 343 LB_GETCURSEL, 0, 0); 344 if (nSel == LB_ERR) return; 345 346 /* 347 * Format: 348 * Width = FontSize.X = LOWORD(FontSize); 349 * Height = FontSize.Y = HIWORD(FontSize); 350 */ 351 FontSize = (ULONG)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTSIZE, 352 LB_GETITEMDATA, nSel, 0); 353 if (FontSize == LB_ERR) return; 354 355 pConInfo->FontSize.X = LOWORD(FontSize); 356 pConInfo->FontSize.Y = HIWORD(FontSize); 357 DPRINT1("pConInfo->FontSize = (%d x %d)\n", pConInfo->FontSize.X, pConInfo->FontSize.Y); 358 359 InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE); 360 InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE); 361 362 swprintf(FontSizeStr, L"%2d", pConInfo->FontSize.X); 363 SetWindowText(GetDlgItem(hwndDlg, IDC_FONT_SIZE_X), FontSizeStr); 364 swprintf(FontSizeStr, L"%2d", pConInfo->FontSize.Y); 365 SetWindowText(GetDlgItem(hwndDlg, IDC_FONT_SIZE_Y), FontSizeStr); 366 } 367 368 369 INT_PTR 370 CALLBACK 371 FontProc(HWND hwndDlg, 372 UINT uMsg, 373 WPARAM wParam, 374 LPARAM lParam) 375 { 376 UNREFERENCED_PARAMETER(wParam); 377 378 switch (uMsg) 379 { 380 case WM_INITDIALOG: 381 { 382 HDC hDC; 383 LOGFONTW lf; 384 INT idx; 385 386 ZeroMemory(&lf, sizeof(lf)); 387 lf.lfCharSet = DEFAULT_CHARSET; // OEM_CHARSET; 388 // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; 389 390 hDC = GetDC(NULL); 391 EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontNamesProc, 392 (LPARAM)GetDlgItem(hwndDlg, IDC_LBOX_FONTTYPE), 0); 393 ReleaseDC(NULL, hDC); 394 395 DPRINT1("ConInfo->FaceName = '%S'\n", ConInfo->FaceName); 396 idx = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, 397 LB_FINDSTRINGEXACT, 0, (LPARAM)ConInfo->FaceName); 398 if (idx != LB_ERR) SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, 399 LB_SETCURSEL, (WPARAM)idx, 0); 400 401 FontTypeChange(hwndDlg, ConInfo); 402 403 return TRUE; 404 } 405 406 case WM_DRAWITEM: 407 { 408 LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam; 409 410 if (drawItem->CtlID == IDC_STATIC_FONT_WINDOW_PREVIEW) 411 PaintConsole(drawItem, ConInfo); 412 else if (drawItem->CtlID == IDC_STATIC_SELECT_FONT_PREVIEW) 413 PaintText(drawItem, ConInfo, Screen); 414 415 return TRUE; 416 } 417 418 case WM_NOTIFY: 419 { 420 switch (((LPNMHDR)lParam)->code) 421 { 422 case PSN_APPLY: 423 { 424 ApplyConsoleInfo(hwndDlg); 425 return TRUE; 426 } 427 } 428 429 break; 430 } 431 432 case WM_COMMAND: 433 { 434 switch (HIWORD(wParam)) 435 { 436 case LBN_SELCHANGE: 437 { 438 switch (LOWORD(wParam)) 439 { 440 case IDC_LBOX_FONTTYPE: 441 { 442 FontTypeChange(hwndDlg, ConInfo); 443 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 444 break; 445 } 446 447 case IDC_LBOX_FONTSIZE: 448 { 449 FontSizeChange(hwndDlg, ConInfo); 450 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 451 break; 452 } 453 } 454 455 break; 456 } 457 } 458 459 break; 460 } 461 462 default: 463 break; 464 } 465 466 return FALSE; 467 } 468