Beispiel #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);
            }
        }
        private void Loop()
        {
            display = X11lib.XOpenDisplay(null);
            if (display == IntPtr.Zero)
            {
                return;
            }
            if (window == IntPtr.Zero)
            {
                int res = 0;
                X11lib.XGetInputFocus(display, ref window, ref res);
                if (window == IntPtr.Zero)
                {
                    return;
                }
            }

            // TODO: move grabkeyboard to separate class
            bool grabKeyboard = false;

            if (grabKeyboard)
            {
                var rootWindow = X11lib.XDefaultRootWindow(display);
                window = X11lib.XCreateSimpleWindow(display, rootWindow, -1, -1, 1, 1, 0, X11lib.XBlackPixel(display, 0), X11lib.XWhitePixel(display, 0));
                X11lib.XLowerWindow(display, window);
            }

            X11lib.XSelectInput(display, window,
                                EventMask.StructureNotifyMask
                                | EventMask.ExposureMask
                                | EventMask.KeyPressMask
                                | EventMask.KeyReleaseMask
                                | EventMask.EnterWindowMask
                                | EventMask.LeaveWindowMask
                                | EventMask.FocusChangeMask
                                | EventMask.PropertyChangeMask
                                | EventMask.VisibilityChangeMask
                                );
            X11lib.XMapWindow(display, window);

            if (grabKeyboard)
            {
                var e2 = new XEvent {
                    type = XEventName.None
                };
                do
                {
                    X11lib.XNextEvent(display, ref e2);
                } while (e2.type != XEventName.MapNotify);

                X11lib.XGrabKeyboard(display, window, false, 1, 1, 0);
                X11lib.XLowerWindow(display, window);
            }

            var e = new XEvent {
                type = XEventName.None
            };

            do
            {
                switch (e.type)
                {
                case XEventName.ConfigureNotify:
                    OnConfigure();
                    break;

                case XEventName.Expose:
                    // The count member is set to the number of Expose events that are to follow.
                    // If count is zero, no more Expose events follow for this window.
                    // However, if count is nonzero, at least that number of Expose events (and possibly more) follow for this window.
                    // Simple applications that do not want to optimize redisplay by distinguishing between subareas of its window
                    // can just ignore all Expose events with nonzero counts and perform full redisplays on events with zero counts.
                    if (e.ExposeEvent.count == 0)
                    {
                        OnExpose();
                    }
                    break;

                case XEventName.KeyPress:
                    //var mod = (Modifier) X.XkbKeysymToModifiers(display, X.XKeycodeToKeysym(display, e.KeyEvent.keycode, 0));
                    OnKeyPress((Key)X11lib.XKeycodeToKeysym(display, e.KeyEvent.keycode, 0));
                    break;

                case XEventName.KeyRelease:
                    OnKeyRelease((Key)X11lib.XKeycodeToKeysym(display, e.KeyEvent.keycode, 0));
                    break;

                case XEventName.EnterNotify:
                    OnEnterLeave(true);
                    break;

                case XEventName.LeaveNotify:
                    OnEnterLeave(false);
                    break;

                case XEventName.FocusIn:
                    OnFocus(true);
                    break;

                case XEventName.FocusOut:
                    OnFocus(false);
                    break;

                case XEventName.PropertyNotify:
                    // state - PropertyNewValue or PropertyDelete
                    OnProperty(e.PropertyEvent.state);
                    break;

                case XEventName.VisibilityNotify:
                    OnVisibility();
                    break;

                case XEventName.ClientMessage:
                    OnClientMessage();
                    break;
                }
                X11lib.XNextEvent(display, ref e);
            } while (!stop);
            X11lib.XCloseDisplay(display);
            display = IntPtr.Zero;
            window  = IntPtr.Zero;
        }