Menu

#43 Adapt to user requested font changes in Tk on Windows

closed-out-of-date
8
2015-02-17
2000-11-01
No

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

Discussion

  • Don Porter

    Don Porter - 2001-03-23
    • labels: 104334 -->
    • milestone: 102488 -->
     
  • Don Porter

    Don Porter - 2001-03-23
    • labels: --> 47. Win Fonts
     
  • Donal K. Fellows

    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...

     
  • Donal K. Fellows

    • priority: 5 --> 8
     
  • Don Porter

    Don Porter - 2003-11-13
    • assigned_to: nobody --> jenglish
     
  • Pat Thoyts

    Pat Thoyts - 2007-08-21

    Logged In: YES
    user_id=202636
    Originator: NO

    This got handled by TIP #145 (named fonts)

     
  • Pat Thoyts

    Pat Thoyts - 2007-08-21
    • status: open --> closed-out-of-date