mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-22 05:48:01 +01:00
WPrefs tries to use the fonts listed in the WMCreateFont() call (from WPrefs.c),
font = WMCreateFont(scr, "Lucida Sans,URW Gothic L,Times New Roman,serif"
":bold:pixelsize=26:antialias=true");
and 'font' is later used without accounting the possibility of it being NULL in
WMSetLabelFont(WPrefs.nameL, font);
WMReleaseFont(font);
In particular, WMReleaseFont(font) will kill WPrefs ungracefully with the
following message if font=NULL
WPrefs: wfont.c:193: WMReleaseFont: Assertion `font!=((void *)0)' failed.
Aborted
That happens because the return value of WMCreateFont() can be NULL, so this
patch makes WMCreateFont() never return NULL. If the font creation fails for
some reason (see below), we try to use the emergency DEFAULT_FONT and print
debugging information telling what's going on. If the use of DEFAULT_FONT
also fails, then we terminate WPrefs with exit(1) and let the user know
why exactly if failed.
This bug happened because the font "Lucida Sans" (the first possibility
in the initial call to WMCreateFont()) "exists" in my system as a stale
symbolic link to a location which no longer exists after an upgrade from
java from 1.5.0.14 to 1.5.0.15
/etc/alternatives/LucidaSansDemiBold.ttf ->
/usr/lib/jvm/java-1.5.0-sun-1.5.0.14/jre/lib/fonts/LucidaSansDemiBold.ttf
So the call to XftFontOpenName(display, scrPtr->screen, fname) with
"Lucida Sans" being the first possibility for Xft to try out ended up in 'font'
being NULL because, as far as the Xft library was concerned, "Lucida Sans"
produced a positive match (due to it existing as a symbolic link) but in the end
a NULL result was produced due to the missing symbolic link destination. This later
exposed the bug of WMCreateFont() returning font=NULL and WPrefs.c not checking
whether font=NULL before using it. Bang!
If "Lucida Sans" was the _second_ entry to try and the first one had suceeded,
this bug would not have surfaced.
This solves https://qa.mandriva.com/show_bug.cgi?id=39677
Signed-off-by: Carlos R. Mafra <crmafra@ift.unesp.br>
406 lines
8.6 KiB
C
406 lines
8.6 KiB
C
|
|
#include <stdlib.h>
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include "WINGsP.h"
|
|
|
|
#include <wraster.h>
|
|
#include <assert.h>
|
|
#include <X11/Xlocale.h>
|
|
|
|
#include <X11/Xft/Xft.h>
|
|
#include <fontconfig/fontconfig.h>
|
|
|
|
|
|
#define DEFAULT_FONT "sans serif:pixelsize=12"
|
|
|
|
#define DEFAULT_SIZE WINGsConfiguration.defaultFontSize
|
|
|
|
|
|
static FcPattern*
|
|
xlfdToFcPattern(char *xlfd)
|
|
{
|
|
FcPattern *pattern;
|
|
char *fname, *ptr;
|
|
|
|
/* Just skip old font names that contain %d in them.
|
|
* We don't support that anymore. */
|
|
if (strchr(xlfd, '%')!=NULL)
|
|
return FcNameParse((FcChar8*)DEFAULT_FONT);
|
|
|
|
fname= wstrdup(xlfd);
|
|
if ((ptr = strchr(fname, ','))) {
|
|
*ptr = 0;
|
|
}
|
|
pattern = XftXlfdParse(fname, False, False);
|
|
wfree(fname);
|
|
|
|
if (!pattern) {
|
|
wwarning(_("invalid font: %s. Trying '%s'"), xlfd, DEFAULT_FONT);
|
|
pattern = FcNameParse((FcChar8*)DEFAULT_FONT);
|
|
}
|
|
|
|
return pattern;
|
|
}
|
|
|
|
|
|
static char*
|
|
xlfdToFcName(char *xlfd)
|
|
{
|
|
FcPattern *pattern;
|
|
char *fname;
|
|
|
|
pattern = xlfdToFcPattern(xlfd);
|
|
fname = (char*)FcNameUnparse(pattern);
|
|
FcPatternDestroy(pattern);
|
|
|
|
return fname;
|
|
}
|
|
|
|
|
|
static Bool
|
|
hasProperty(FcPattern *pattern, const char *property)
|
|
{
|
|
FcValue val;
|
|
|
|
if (FcPatternGet(pattern, property, 0, &val)==FcResultMatch) {
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
|
|
static Bool
|
|
hasPropertyWithStringValue(FcPattern *pattern, const char *object, char *value)
|
|
{
|
|
FcChar8 *str;
|
|
int id;
|
|
|
|
if (!value || value[0]==0)
|
|
return True;
|
|
|
|
id = 0;
|
|
while (FcPatternGetString(pattern, object, id, &str)==FcResultMatch) {
|
|
if (strcasecmp(value, (char*)str) == 0) {
|
|
return True;
|
|
}
|
|
id++;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
|
|
static char*
|
|
makeFontOfSize(char *font, int size, char *fallback)
|
|
{
|
|
FcPattern *pattern;
|
|
char *result;
|
|
|
|
if (font[0]=='-') {
|
|
pattern = xlfdToFcPattern(font);
|
|
} else {
|
|
pattern = FcNameParse((FcChar8*)font);
|
|
}
|
|
|
|
/*FcPatternPrint(pattern);*/
|
|
|
|
if (size > 0) {
|
|
FcPatternDel(pattern, FC_PIXEL_SIZE);
|
|
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)size);
|
|
} else if (size==0 && !hasProperty(pattern, "size") &&
|
|
!hasProperty(pattern, FC_PIXEL_SIZE)) {
|
|
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)DEFAULT_SIZE);
|
|
}
|
|
|
|
if (fallback && !hasPropertyWithStringValue(pattern, FC_FAMILY, fallback)) {
|
|
FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)fallback);
|
|
}
|
|
|
|
/*FcPatternPrint(pattern);*/
|
|
|
|
result = (char*)FcNameUnparse(pattern);
|
|
FcPatternDestroy(pattern);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
WMFont*
|
|
WMCreateFont(WMScreen *scrPtr, char *fontName)
|
|
{
|
|
Display *display = scrPtr->display;
|
|
WMFont *font;
|
|
char *fname;
|
|
|
|
if (fontName[0]=='-'){
|
|
fname = xlfdToFcName(fontName);
|
|
} else {
|
|
fname = wstrdup(fontName);
|
|
}
|
|
|
|
if (!WINGsConfiguration.antialiasedText && !strstr(fname, ":antialias=")) {
|
|
fname = wstrappend(fname, ":antialias=false");
|
|
}
|
|
|
|
font = WMHashGet(scrPtr->fontCache, fname);
|
|
if (font) {
|
|
WMRetainFont(font);
|
|
wfree(fname);
|
|
return font;
|
|
}
|
|
|
|
font = wmalloc(sizeof(WMFont));
|
|
memset(font, 0, sizeof(WMFont));
|
|
|
|
font->screen = scrPtr;
|
|
|
|
font->font = XftFontOpenName(display, scrPtr->screen, fname);
|
|
if (!font->font) {
|
|
printf("Font named %s doesn't exist.\n", fname);
|
|
printf("Please check your system configuration.\n");
|
|
printf("Will try default font %s.\n", DEFAULT_FONT);
|
|
font->font = XftFontOpenName(display, scrPtr->screen, DEFAULT_FONT);
|
|
if (!font->font) {
|
|
printf("Unrecoverable font error! I must die!\n");
|
|
exit(1);
|
|
} else
|
|
printf("Default font loading succeded.\n");
|
|
}
|
|
|
|
font->height = font->font->ascent+font->font->descent;
|
|
font->y = font->font->ascent;
|
|
|
|
font->refCount = 1;
|
|
|
|
font->name = fname;
|
|
|
|
assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
|
|
|
|
return font;
|
|
}
|
|
|
|
|
|
WMFont*
|
|
WMRetainFont(WMFont *font)
|
|
{
|
|
wassertrv(font!=NULL, NULL);
|
|
|
|
font->refCount++;
|
|
|
|
return font;
|
|
}
|
|
|
|
|
|
void
|
|
WMReleaseFont(WMFont *font)
|
|
{
|
|
wassertr(font!=NULL);
|
|
|
|
font->refCount--;
|
|
if (font->refCount < 1) {
|
|
XftFontClose(font->screen->display, font->font);
|
|
if (font->name) {
|
|
WMHashRemove(font->screen->fontCache, font->name);
|
|
wfree(font->name);
|
|
}
|
|
wfree(font);
|
|
}
|
|
}
|
|
|
|
|
|
Bool
|
|
WMIsAntialiasingEnabled(WMScreen *scrPtr)
|
|
{
|
|
return scrPtr->antialiasedText;
|
|
}
|
|
|
|
|
|
unsigned int
|
|
WMFontHeight(WMFont *font)
|
|
{
|
|
wassertrv(font!=NULL, 0);
|
|
|
|
return font->height;
|
|
}
|
|
|
|
|
|
char*
|
|
WMGetFontName(WMFont *font)
|
|
{
|
|
wassertrv(font!=NULL, NULL);
|
|
|
|
return font->name;
|
|
}
|
|
|
|
|
|
WMFont*
|
|
WMDefaultSystemFont(WMScreen *scrPtr)
|
|
{
|
|
return WMRetainFont(scrPtr->normalFont);
|
|
}
|
|
|
|
|
|
WMFont*
|
|
WMDefaultBoldSystemFont(WMScreen *scrPtr)
|
|
{
|
|
return WMRetainFont(scrPtr->boldFont);
|
|
}
|
|
|
|
|
|
WMFont*
|
|
WMSystemFontOfSize(WMScreen *scrPtr, int size)
|
|
{
|
|
WMFont *font;
|
|
char *fontSpec;
|
|
|
|
fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, NULL);
|
|
|
|
font = WMCreateFont(scrPtr, fontSpec);
|
|
|
|
if (!font) {
|
|
wwarning(_("could not load font: %s."), fontSpec);
|
|
}
|
|
|
|
wfree(fontSpec);
|
|
|
|
return font;
|
|
}
|
|
|
|
|
|
WMFont*
|
|
WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
|
|
{
|
|
WMFont *font;
|
|
char *fontSpec;
|
|
|
|
fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, NULL);
|
|
|
|
font = WMCreateFont(scrPtr, fontSpec);
|
|
|
|
if (!font) {
|
|
wwarning(_("could not load font: %s."), fontSpec);
|
|
}
|
|
|
|
wfree(fontSpec);
|
|
|
|
return font;
|
|
}
|
|
|
|
|
|
int
|
|
WMWidthOfString(WMFont *font, char *text, int length)
|
|
{
|
|
XGlyphInfo extents;
|
|
|
|
wassertrv(font!=NULL && text!=NULL, 0);
|
|
|
|
XftTextExtentsUtf8(font->screen->display, font->font,
|
|
(XftChar8 *)text, length, &extents);
|
|
|
|
return extents.xOff; /* don't ask :P */
|
|
}
|
|
|
|
|
|
|
|
void
|
|
WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
|
|
int x, int y, char *text, int length)
|
|
{
|
|
XftColor xftcolor;
|
|
|
|
wassertr(font!=NULL);
|
|
|
|
xftcolor.color.red = color->color.red;
|
|
xftcolor.color.green = color->color.green;
|
|
xftcolor.color.blue = color->color.blue;
|
|
xftcolor.color.alpha = color->alpha;;
|
|
xftcolor.pixel = W_PIXEL(color);
|
|
|
|
XftDrawChange(scr->xftdraw, d);
|
|
|
|
XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font,
|
|
x, y + font->y, (XftChar8*)text, length);
|
|
}
|
|
|
|
|
|
void
|
|
WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
|
|
WMFont *font, int x, int y, char *text, int length)
|
|
{
|
|
XftColor textColor;
|
|
XftColor bgColor;
|
|
|
|
wassertr(font!=NULL);
|
|
|
|
textColor.color.red = color->color.red;
|
|
textColor.color.green = color->color.green;
|
|
textColor.color.blue = color->color.blue;
|
|
textColor.color.alpha = color->alpha;;
|
|
textColor.pixel = W_PIXEL(color);
|
|
|
|
bgColor.color.red = background->color.red;
|
|
bgColor.color.green = background->color.green;
|
|
bgColor.color.blue = background->color.blue;
|
|
bgColor.color.alpha = background->alpha;;
|
|
bgColor.pixel = W_PIXEL(background);
|
|
|
|
XftDrawChange(scr->xftdraw, d);
|
|
|
|
XftDrawRect(scr->xftdraw, &bgColor, x, y,
|
|
WMWidthOfString(font, text, length),
|
|
font->height);
|
|
|
|
XftDrawStringUtf8(scr->xftdraw, &textColor, font->font,
|
|
x, y + font->y, (XftChar8*)text, length);
|
|
}
|
|
|
|
|
|
WMFont*
|
|
WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style)
|
|
{
|
|
FcPattern *pattern;
|
|
WMFont *copy;
|
|
char *name;
|
|
|
|
if (!font)
|
|
return NULL;
|
|
|
|
/* It's enough to add italic to slant, even if the font has no italic
|
|
* variant, but only oblique. This is because fontconfig will actually
|
|
* return the closest match font to what we requested which is the
|
|
* oblique font. Same goes for using bold for weight.
|
|
*/
|
|
pattern = FcNameParse((FcChar8*)WMGetFontName(font));
|
|
switch (style) {
|
|
case WFSNormal:
|
|
FcPatternDel(pattern, FC_WEIGHT);
|
|
FcPatternDel(pattern, FC_SLANT);
|
|
break;
|
|
case WFSBold:
|
|
FcPatternDel(pattern, FC_WEIGHT);
|
|
FcPatternAddString(pattern, FC_WEIGHT, (FcChar8*)"bold");
|
|
break;
|
|
case WFSItalic:
|
|
FcPatternDel(pattern, FC_SLANT);
|
|
FcPatternAddString(pattern, FC_SLANT, (FcChar8*)"italic");
|
|
break;
|
|
case WFSBoldItalic:
|
|
FcPatternDel(pattern, FC_WEIGHT);
|
|
FcPatternDel(pattern, FC_SLANT);
|
|
FcPatternAddString(pattern, FC_WEIGHT, (FcChar8*)"bold");
|
|
FcPatternAddString(pattern, FC_SLANT, (FcChar8*)"italic");
|
|
break;
|
|
}
|
|
|
|
name = (char*)FcNameUnparse(pattern);
|
|
copy = WMCreateFont(scrPtr, name);
|
|
FcPatternDestroy(pattern);
|
|
wfree(name);
|
|
|
|
return copy;
|
|
}
|
|
|