Ejemplo n.º 1
0
        // ###############################################################################
        // ### 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);
            }
        }