// ############################################################################### // ### M E T H O D S // ############################################################################### #region Methods /// <summary>Prepare a font or fonteset for utilization with Xrw.</summary> /// <param name="fontSpecification">The font specification, that identifies a font/fontset.<see cref="System.String"/></param> /// <param name="x11display">The display pointer, that specifies the connection to the X server.<see cref="IntPtr"/></param> /// <param name="useFontset">The flag defining whether to use a fontset or a single font.<see cref="System.Boolean"/></param> /// <param name="fontData">The resulting font data on success, or null otherwise.<see cref="X11.X11FontData"/></param> /// <returns>True on success, or false otherwise.<see cref="System.Boolean"/></returns> public static bool PrepareFont(string fontSpecification, IntPtr x11display, bool useFontset, ref X11.X11FontData fontData) { fontData = null; foreach (KeyValuePair <FontDataKey, X11FontData> loadedFont in _loadedFonts) { if (loadedFont.Key.FontSpecification == fontSpecification && loadedFont.Key.X11Display == x11display && loadedFont.Key.UseFontset) { fontData = loadedFont.Value; return(true); } } FontDataKey key = new FontDataKey(fontSpecification, x11display, useFontset); if (useFontset) { IntPtr missingCharsetList; TInt missingCharsetCount; X11.XID fontsetResourceId = X11lib.XCreateFontSet(x11display, fontSpecification, out missingCharsetList, out missingCharsetCount, IntPtr.Zero); // Check whether directly matching fontset has been loaded, and - if not - load the most similar fontset (fuzzy). int fuzzyFactor = 0; string fuzzyFontSpecification = (fontsetResourceId == (X11.XID) 0 ? fontSpecification : null); while (fontsetResourceId == (X11.XID) 0 && fuzzyFactor < 3) { string lastFuzzyFontSpecification = fuzzyFontSpecification; if (fuzzyFactor == 0) { fuzzyFontSpecification = X11FontData.ModifyFontSpecificationStretch(fuzzyFontSpecification, "*"); } if (fuzzyFactor == 1) { fuzzyFontSpecification = X11FontData.ModifyFontSpecificationWieght(fuzzyFontSpecification, "*"); } if (fuzzyFactor == 2) { fuzzyFontSpecification = X11FontData.ModifyFontSpecificationSlant(fuzzyFontSpecification, "*"); } fuzzyFactor++; // Safe time if no change has been made. if (lastFuzzyFontSpecification == fuzzyFontSpecification) { continue; } if (!string.IsNullOrEmpty(lastFuzzyFontSpecification) && lastFuzzyFontSpecification.Trim() != "") { fontsetResourceId = X11lib.XCreateFontSet(x11display, fuzzyFontSpecification, out missingCharsetList, out missingCharsetCount, IntPtr.Zero); if (fontsetResourceId != (X11.XID) 0) { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Fuzzy load fontset with specification '" + fuzzyFontSpecification + "' " + "instead of '" + fontSpecification + "' succeeded."); } } } // Check whether directly matching or most similar fontset has been loaded, and - if not - load a fallback fontset. string extFontSpecification = null; if (fontsetResourceId == (X11.XID) 0) { // Let the font server guess a fallback fontset. if (!string.IsNullOrEmpty(fontSpecification) && fontSpecification.Trim() != "" && !fontSpecification.Trim().EndsWith(",*")) { extFontSpecification = fontSpecification + ",*"; SimpleLog.LogLine(TraceEventType.Warning, CLASS_NAME + "::PrepareFont () Can not load a fontset with specification '" + fontSpecification + "'."); SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Retry to load a fontset with specification '" + extFontSpecification + "'."); fontsetResourceId = X11lib.XCreateFontSet(x11display, extFontSpecification, out missingCharsetList, out missingCharsetCount, IntPtr.Zero); } // The font specification already includs a joker to guess a fallback fontset. else { SimpleLog.LogLine(TraceEventType.Error, CLASS_NAME + "::PrepareFont () Can not load a fontset with specification '" + fontSpecification + "'."); // No success at all - even with a guess of a fallback fontset! return(false); } } // Check whether matching fontset has been loaded. if (fontsetResourceId == (X11.XID) 0) { SimpleLog.LogLine(TraceEventType.Error, CLASS_NAME + "::PrepareFont () Can not load a fontset with specification '" + extFontSpecification + "'."); // No success at all - even with a guess of a fallback fontset! return(false); } if (!string.IsNullOrEmpty(extFontSpecification)) { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Successfully loaded best matching fontset for specification '" + fontSpecification + "' " + "using specification '" + extFontSpecification + "'."); } else if (!string.IsNullOrEmpty(fuzzyFontSpecification)) { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Successfully loaded best matching fontset for specification '" + fontSpecification + "' " + "using specification '" + fuzzyFontSpecification + "'."); } else { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Successfully loaded best matching fontset for specification '" + fontSpecification + "'."); } for (int countCharSet = 0; countCharSet < (int)missingCharsetCount; countCharSet++) { IntPtr p = Marshal.ReadIntPtr(missingCharsetList, countCharSet * Marshal.SizeOf(typeof(IntPtr))); string s = Marshal.PtrToStringAuto(p); if (!string.IsNullOrEmpty(extFontSpecification)) { SimpleLog.LogLine(TraceEventType.Warning, CLASS_NAME + "::PrepareFont () Fontset for specification '" + extFontSpecification + "' is missing font for charset '" + s + "'."); } else if (!string.IsNullOrEmpty(fuzzyFontSpecification)) { SimpleLog.LogLine(TraceEventType.Warning, CLASS_NAME + "::PrepareFont () Fontset for specification '" + fuzzyFontSpecification + "' is missing font for charset '" + s + "'."); } else { SimpleLog.LogLine(TraceEventType.Warning, CLASS_NAME + "::PrepareFont () Fontset for specification '" + fontSpecification + "' is missing font for charset '" + s + "'."); } } // Calculate maximum font height, ascent and descent. int ascent = 0; int descent = 0; X11lib.XFontSetExtents extents = X11lib.XExtentsOfFontSet(fontsetResourceId); X11lib.XFontStruct[] fontStructArray; string[] fontNameArray; int maxFonts; maxFonts = X11lib.XFontsOfFontSet(fontsetResourceId, out fontStructArray, out fontNameArray); for (int countFonts = 0; countFonts < maxFonts; countFonts++) { if (ascent < (int)fontStructArray[countFonts].ascent) { ascent = (int)fontStructArray[countFonts].ascent; } if (descent < (int)fontStructArray[countFonts].descent) { descent = (int)fontStructArray[countFonts].descent; } } string finalFontSpecification = null; if (!string.IsNullOrEmpty(extFontSpecification)) { finalFontSpecification = extFontSpecification; } else if (!string.IsNullOrEmpty(fuzzyFontSpecification)) { finalFontSpecification = fuzzyFontSpecification; } else { finalFontSpecification = fontSpecification; } // Maximum font height, ascent and descent might be frequently used for calculation. fontData = X11FontData.NewFontSetData(finalFontSpecification, x11display, fontsetResourceId, (int)extents.max_logical_extent.height, ascent, descent); IntPtr gc = X11lib.XCreateGC(x11display, X11lib.XDefaultRootWindow(x11display), 0, IntPtr.Zero); if (gc != IntPtr.Zero) { fontData.SetTypicalCharWidth(AverageCharacterWidth(x11display, gc, fontData)); X11lib.XFreeGC(x11display, gc); } _loadedFonts.Add(key, fontData); return(true); } // Use font, if fontset isn't supported. else // of (useFontset) { // Load font and query font structure (to get maximum font height, ascent and descent). IntPtr fontStructure = X11lib.XLoadQueryFont(x11display, fontSpecification); // Check whether directly matching font has been loaded, and - if not - load the most similar font (fuzzy). int fuzzyFactor = 0; string fuzzyFontSpecification = (fontStructure == IntPtr.Zero ? fontSpecification : null); while (fontStructure == IntPtr.Zero && fuzzyFactor < 3) { string lastFuzzyFontSpecification = fuzzyFontSpecification; if (fuzzyFactor == 0) { fuzzyFontSpecification = X11FontData.ModifyFontSpecificationStretch(fuzzyFontSpecification, "*"); } if (fuzzyFactor == 1) { fuzzyFontSpecification = X11FontData.ModifyFontSpecificationWieght(fuzzyFontSpecification, "*"); } if (fuzzyFactor == 2) { fuzzyFontSpecification = X11FontData.ModifyFontSpecificationSlant(fuzzyFontSpecification, "*"); } fuzzyFactor++; // Safe time if no change has been made. if (lastFuzzyFontSpecification == fuzzyFontSpecification) { continue; } if (!string.IsNullOrEmpty(lastFuzzyFontSpecification) && lastFuzzyFontSpecification.Trim() != "") { fontStructure = X11lib.XLoadQueryFont(x11display, lastFuzzyFontSpecification); if (fontStructure != IntPtr.Zero) { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Fuzzy load font with specification '" + fuzzyFontSpecification + "' " + "instead of '" + fontSpecification + "' succeeded."); } } } // Check whether directly matching or most similar font has been loaded, and - if not - load a fallback font. string extFontSpecification = null; if (fontStructure != IntPtr.Zero) { // Let the font server guess a fallback fontset. if (!string.IsNullOrEmpty(fontSpecification) && fontSpecification.Trim() != "" && !fontSpecification.Trim().EndsWith(",*")) { extFontSpecification = fontSpecification + ",*"; SimpleLog.LogLine(TraceEventType.Warning, CLASS_NAME + "::PrepareFont () Can not load a fontset with specification '" + fontSpecification + "'."); SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Retry to load a fontset with specification '" + extFontSpecification + "'."); fontStructure = X11lib.XLoadQueryFont(x11display, extFontSpecification); } // The font specification already includs a joker to guess a fallback fontset. else { SimpleLog.LogLine(TraceEventType.Error, CLASS_NAME + "::PrepareFont () Can not load a font with specification '" + fontSpecification + "'."); // No success at all - even with a guess of a fallback font! return(false); } } // Check whether matching font has been loaded. if (fontStructure == IntPtr.Zero) { SimpleLog.LogLine(TraceEventType.Error, CLASS_NAME + "::PrepareFont () Can not load a font with specification '" + fontSpecification + "'."); // No success at all - even with a guess of a fallback font! return(false); } if (!string.IsNullOrEmpty(extFontSpecification)) { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Successfully loaded best matching font for specification '" + fontSpecification + "' " + "using specification '" + extFontSpecification + "'."); } else if (!string.IsNullOrEmpty(fuzzyFontSpecification)) { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Successfully loaded best matching font for specification '" + fontSpecification + "' " + "using specification '" + fuzzyFontSpecification + "'."); } else { SimpleLog.LogLine(TraceEventType.Information, CLASS_NAME + "::PrepareFont () Successfully loaded best matching font for specification '" + fontSpecification + "'."); } X11lib.XFontStruct fs = (X11lib.XFontStruct)Marshal.PtrToStructure(fontStructure, typeof(X11lib.XFontStruct)); string finalFontSpecification = null; if (!string.IsNullOrEmpty(extFontSpecification)) { finalFontSpecification = extFontSpecification; } else if (!string.IsNullOrEmpty(fuzzyFontSpecification)) { finalFontSpecification = fuzzyFontSpecification; } else { finalFontSpecification = fontSpecification; } // Maximum font height, ascent and descent might be frequently used for calculation. fontData = X11FontData.NewSingleFontData(finalFontSpecification, x11display, fs.fid, (int)fs.ascent + (int)fs.descent, (int)fs.ascent, (int)fs.descent); IntPtr gc = X11lib.XCreateGC(x11display, X11lib.XDefaultRootWindow(x11display), 0, IntPtr.Zero); if (gc != IntPtr.Zero) { fontData.SetTypicalCharWidth(AverageCharacterWidth(x11display, gc, fontData)); X11lib.XFreeGC(x11display, gc); } _loadedFonts.Add(key, fontData); return(true); } }