OriginalBugID: 599 RFE
Version: 8.0p2
SubmitDate: '1998-05-21'
LastModified: '2000-04-03'
Severity: SER
Status: Assigned
Submitter: hershey
ChangedBy: ericm
OS: All Windows
OSVersion: NA
Machine: NA
FixedInVersion: NA
One of the oddities of using Tk on Windows can be seen by using the
control panel to change your standard fonts.
Do this from the Display control panel, click on the Appearance tab,
and select an item such as ``Menu''. You'll see that you can change
the font. If you do this, you'll see the running applications adapt
to your change. Except the ones running Tk.
Here is the start of a patch to make Tk adapt to font changes.
Changing the font in the control panel sends a WM_SETTINGCHANGE
message to all programs with a parameter of SPI_SETNONCLIENTMETRICS.
The program is supposed to fetch the new non-client metrics, and adapt
accordingly.
There are five fonts defined in the NONCLIENTMETRICS structure: the
caption font, the small caption font, the menu font, the status bar
font, and the message box font.
This patch introduces five magic font families to match the five
Windows non-client fonts found in the NONCLIENTMETRICS structure.
With this patch, if you use a font in one of these magic families,
then it will automatically adapt to changes the user makes using the
control panel.
For example, to make menus use the correct, user-selected, font, and
to adapt to user requested changes correctly, you might do something
like this:
font create menufont -family windows-menu
option add *Menu.Font menufont
(This is what we are doing in our applications.)
This patch is not complete because it does not change the default
behaviour to use these new fonts, and because it does not update the
documentation. However, this functionality is fairly important for
correct behaviour on Windows, and this patch should serve as a good
start for implementing it.
Ian Taylor
ian@cygnus.com
*** /5g/ian/tk8.0p2/generic/tkFont.c Fri Oct 10 20:04:59 1997
--- generic/tkFont.c Thu Apr 16 12:41:39 1998
*************** NewChunk(layoutPtrPtr, maxPtr, start, nu
*** 3005,3008 ****
--- 3005,3051 ----
return chunkPtr;
}
+
+ /*
+ *---------------------------------------------------------------------------
+ *
+ * TkUpdateFonts --
+ *
+ * Check all fonts to see whether they have changed. The check
+ * is done by calling a function pointer passed to this routine.
+ *
+ * This is used on Windows if the user changes the standard fonts
+ * using the control panel.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Calls the passed in function pointer for each font, which may
+ * have side effects. Calls UpdateDependantFonts for each font
+ * that has changed.
+ *
+ *---------------------------------------------------------------------------
+ */
+ void
+ TkUpdateFonts(tkwin, changed)
+ Tk_Window tkwin;
+ int (*changed) _ANSI_ARGS_((TkFontAttributes *faPtr));
+ {
+ TkFontInfo *fiPtr;
+ Tcl_HashEntry *namedHashPtr;
+ Tcl_HashSearch search;
+ NamedFont *nfPtr;
+
+ fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
+
+ namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
+ while (namedHashPtr != NULL) {
+ nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
+ if ((*changed)(&nfPtr->fa)) {
+ UpdateDependantFonts(fiPtr, tkwin, namedHashPtr);
+ }
+ namedHashPtr = Tcl_NextHashEntry(&search);
+ }
+ }
*** /5g/ian/tk8.0p2/generic/tkFont.h Thu May 15 20:14:13 1997
--- generic/tkFont.h Thu Apr 16 12:42:38 1998
*************** EXTERN void TkInitFontAttributes _ANSI_
*** 190,195 ****
--- 190,197 ----
TkFontAttributes *faPtr));
EXTERN int TkParseXLFD _ANSI_ARGS_((CONST char *string,
TkXLFDAttributes *xaPtr));
+ EXTERN void TkUpdateFonts _ANSI_ARGS_((Tk_Window tkwin,
+ int (*changed) (TkFontAttributes *faPtr)));
/*
* Common APIs exported to tkFont.c from all platform-specific
*** /5g/ian/tk8.0p2/win/tkWinFont.c Thu May 15 20:15:03 1997
--- win/tkWinFont.c Thu Apr 16 12:47:23 1998
*************** static TkStateMap systemMap[] = {
*** 44,49 ****
--- 44,63 ----
{-1, NULL}
};
+ /*
+ * Map magic Windows font names into offsets into a NONCLIENTMETRICS
+ * structure.
+ */
+
+ static TkStateMap nonClientMap[] = {
+ {Tk_Offset(NONCLIENTMETRICS, lfCaptionFont), "caption"},
+ {Tk_Offset(NONCLIENTMETRICS, lfSmCaptionFont), "smcaption"},
+ {Tk_Offset(NONCLIENTMETRICS, lfMenuFont), "menu"},
+ {Tk_Offset(NONCLIENTMETRICS, lfStatusFont), "status"},
+ {Tk_Offset(NONCLIENTMETRICS, lfMessageFont), "message"},
+ {-1, NULL}
+ };
+
#define ABS(x) (((x) < 0) ? -(x) : (x))
static TkFont * AllocFont _ANSI_ARGS_((TkFont *tkFontPtr,
*************** static char * GetProperty _ANSI_ARGS_((
*** 53,59 ****
static int CALLBACK WinFontFamilyEnumProc _ANSI_ARGS_((ENUMLOGFONT *elfPtr,
NEWTEXTMETRIC *ntmPtr, int fontType,
LPARAM lParam));
!
/*
*---------------------------------------------------------------------------
--- 67,73 ----
static int CALLBACK WinFontFamilyEnumProc _ANSI_ARGS_((ENUMLOGFONT *elfPtr,
NEWTEXTMETRIC *ntmPtr, int fontType,
LPARAM lParam));
! static int FontChanged _ANSI_ARGS_((TkFontAttributes *faPtr));
/*
*---------------------------------------------------------------------------
*************** TkpGetFontFromAttributes(tkFontPtr, tkwi
*** 140,194 ****
Tk_Window tkwin; /* For display where font will be used. */
CONST TkFontAttributes *faPtr; /* Set of attributes to match. */
{
LOGFONT lf;
HFONT hFont;
Window window;
HWND hwnd;
HDC hdc;
! window = Tk_WindowId(((TkWindow *) tkwin)->mainPtr->winPtr);
! hwnd = (window == None) ? NULL : TkWinGetHWND(window);
! hdc = GetDC(hwnd);
! lf.lfHeight = -faPtr->pointsize;
! if (lf.lfHeight < 0) {
! lf.lfHeight = MulDiv(lf.lfHeight,
! 254 * WidthOfScreen(Tk_Screen(tkwin)),
! 720 * WidthMMOfScreen(Tk_Screen(tkwin)));
! }
! lf.lfWidth = 0;
! lf.lfEscapement = 0;
! lf.lfOrientation = 0;
! lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;
! lf.lfItalic = faPtr->slant;
! lf.lfUnderline = faPtr->underline;
! lf.lfStrikeOut = faPtr->overstrike;
! lf.lfCharSet = DEFAULT_CHARSET;
! lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
! lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
! lf.lfQuality = DEFAULT_QUALITY;
! lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
! if (faPtr->family == NULL) {
! lf.lfFaceName[0] = '\0';
} else {
! lstrcpyn(lf.lfFaceName, faPtr->family, sizeof(lf.lfFaceName));
! }
! ReleaseDC(hwnd, hdc);
! /*
! * Replace the standard X and Mac family names with the names that
! * Windows likes.
! */
! if ((stricmp(lf.lfFaceName, "Times") == 0)
! || (stricmp(lf.lfFaceName, "New York") == 0)) {
! strcpy(lf.lfFaceName, "Times New Roman");
! } else if ((stricmp(lf.lfFaceName, "Courier") == 0)
! || (stricmp(lf.lfFaceName, "Monaco") == 0)) {
! strcpy(lf.lfFaceName, "Courier New");
! } else if ((stricmp(lf.lfFaceName, "Helvetica") == 0)
! || (stricmp(lf.lfFaceName, "Geneva") == 0)) {
! strcpy(lf.lfFaceName, "Arial");
}
hFont = CreateFontIndirect(&lf);
--- 154,227 ----
Tk_Window tkwin; /* For display where font will be used. */
CONST TkFontAttributes *faPtr; /* Set of attributes to match. */
{
+ int offset;
LOGFONT lf;
HFONT hFont;
Window window;
HWND hwnd;
HDC hdc;
! /*
! * Magic handling for fonts in the windows-* family.
! */
! if (faPtr->family != NULL
! && strncmp(faPtr->family, "windows-", 8) == 0
! && (offset = TkFindStateNum(NULL, NULL, nonClientMap,
! faPtr->family + 8)) >= 0) {
! NONCLIENTMETRICS ncm;
!
! ncm.cbSize = sizeof(ncm);
! if (! SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm),
! (void *) &ncm, 0)) {
! panic("TkpGetFontFromAttributes: SystemParametersInfo failed");
! }
! lf = *(LOGFONT *)((char *) &ncm + offset);
} else {
! window = Tk_WindowId(((TkWindow *) tkwin)->mainPtr->winPtr);
! hwnd = (window == None) ? NULL : TkWinGetHWND(window);
! hdc = GetDC(hwnd);
! lf.lfHeight = -faPtr->pointsize;
! if (lf.lfHeight < 0) {
! lf.lfHeight = MulDiv(lf.lfHeight,
! 254 * WidthOfScreen(Tk_Screen(tkwin)),
! 720 * WidthMMOfScreen(Tk_Screen(tkwin)));
! }
! lf.lfWidth = 0;
! lf.lfEscapement = 0;
! lf.lfOrientation = 0;
! lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;
! lf.lfItalic = faPtr->slant;
! lf.lfUnderline = faPtr->underline;
! lf.lfStrikeOut = faPtr->overstrike;
! lf.lfCharSet = DEFAULT_CHARSET;
! lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
! lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
! lf.lfQuality = DEFAULT_QUALITY;
! lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
! if (faPtr->family == NULL) {
! lf.lfFaceName[0] = '\0';
! } else {
! lstrcpyn(lf.lfFaceName, faPtr->family, sizeof(lf.lfFaceName));
! }
! ReleaseDC(hwnd, hdc);
! /*
! * Replace the standard X and Mac family names with the names that
! * Windows likes.
! */
!
! if ((stricmp(lf.lfFaceName, "Times") == 0)
! || (stricmp(lf.lfFaceName, "New York") == 0)) {
! strcpy(lf.lfFaceName, "Times New Roman");
! } else if ((stricmp(lf.lfFaceName, "Courier") == 0)
! || (stricmp(lf.lfFaceName, "Monaco") == 0)) {
! strcpy(lf.lfFaceName, "Courier New");
! } else if ((stricmp(lf.lfFaceName, "Helvetica") == 0)
! || (stricmp(lf.lfFaceName, "Geneva") == 0)) {
! strcpy(lf.lfFaceName, "Arial");
! }
}
hFont = CreateFontIndirect(&lf);
*************** AllocFont(tkFontPtr, tkwin, hFont)
*** 640,643 ****
--- 673,709 ----
return (TkFont *) fontPtr;
}
+
+ /*
+ *---------------------------------------------------------------------------
+ *
+ * TkWinNCMetricsChanged, FontChanged --
+ *
+ * Called when the non client metrics change to update all the
+ * information for the magic Windows fonts.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Updates font information in generic TkFont code.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+ void
+ TkWinNCMetricsChanged(tkwin)
+ Tk_Window tkwin;
+ {
+ TkUpdateFonts(tkwin, FontChanged);
+ }
+ static int
+ FontChanged(faPtr)
+ TkFontAttributes *faPtr;
+ {
+ return (faPtr->family != NULL
+ && strncmp(faPtr->family, "windows-", 8) == 0
+ && TkFindStateNum(NULL, NULL, nonClientMap,
+ faPtr->family + 8) >= 0);
+ }
*** /5g/ian/tk8.0p2/win/tkWinInt.h Thu Oct 9 13:40:17 1997
--- win/tkWinInt.h Thu Apr 16 12:47:44 1998
*************** extern int TkWinHandleMenuEvent _ANSI_A
*** 165,170 ****
--- 165,171 ----
UINT *pMessage, WPARAM *pwParam, LPARAM *plParam,
LRESULT *plResult));
extern int TkWinIndexOfColor _ANSI_ARGS_((XColor *colorPtr));
+ extern void TkWinNCMetricsChanged _ANSI_ARGS_((Tk_Window tkwin));
extern void TkWinPointerDeadWindow _ANSI_ARGS_((TkWindow *winPtr));
extern void TkWinPointerEvent _ANSI_ARGS_((HWND hwnd, int x,
int y));
*** /5g/ian/tk8.0p2/win/tkWinWm.c Fri Oct 31 12:57:07 1997
--- win/tkWinWm.c Thu Apr 16 12:47:57 1998
*************** WmProc(hwnd, message, wParam, lParam)
*** 3959,3964 ****
--- 3959,3973 ----
result = 0;
goto done;
+ case WM_SETTINGCHANGE:
+ if (wParam == SPI_SETNONCLIENTMETRICS) {
+ winPtr = GetTopLevel(hwnd);
+ if (winPtr != NULL) {
+ TkWinNCMetricsChanged((Tk_Window) winPtr);
+ }
+ }
+ break;
+
default:
break;
}
Good idea, but we should use something like "systemMenuFont" or similar, to emphasize that it is a system font.
- eric
-- 04/03/2000 ericm
Logged In: YES
user_id=79902
Who was working on this area? ISTR there was effort on this
relatively recently, and there's even a mechanism for
indicating to clients of fonts that the world has changed...
Logged In: YES
user_id=202636
Originator: NO
This got handled by TIP #145 (named fonts)