justinmeiners / classic-colors

Paint program for Unix. Inspired by MS Paint (Windows 95-98).
GNU General Public License v2.0
46 stars 3 forks source link

Add support for anti-aliased fonts in user interface #12

Open dpeterc opened 2 years ago

dpeterc commented 2 years ago

Motif does support anti-aliased fonts using XFT. Current default usage of classic-colors does not look as well as it could, and that might deter some users. If you start the program with the following options, you will have the user interface in anti-aliased fonts. classic-colors -xrm "renderTable: rt" -xrm "rtfontType: FONT_IS_XFT" -xrm "rtfontName: Sans" -xrm "rt*fontSize: 10"

Program should do this internally by default, or offer a script for starting the binary with these options. The user could then edit the script to change font typeface and size. Ultimately, the program should read some system default font or offer user interface for selection of default user interface font, but at this early stage, it is probably an overkill.

For XFT font selector, check the source of xnedit https://sourceforge.net/projects/xnedit/ Preferences > Text fonts > Browse

dpeterc commented 2 years ago

This is how the program looks with XFT fonts. Classic-ColorsXFT

justinmeiners commented 2 years ago

I will have a PR up soon that I could use your feedback on.

Here are some resources for myself which helped me understand what this is:

http://www.motifdeveloper.com/tips/tip2.html https://sourceforge.net/p/cdesktopenv/wiki/FontsWithXFT/ https://docs.prolifics.com/panther/html/cfg_html/motifdef.htm https://wiki.gentoo.org/wiki/Xft_support_for_GNU_Emacs https://motif.ics.com/forum/developers/utf8-support

I'll also add the Motif XFT PDF since it's only available on internet archive (and small):

Fonts_UTF-8_WhitePaperv6.pdf

justinmeiners commented 2 years ago

This is a great suggestion. What do you think about the solution in PR #14 ?

dpeterc commented 2 years ago

I think the solution is fine.

As XFT was added to Motif in the sunset of its active development, the documentation is very scarce. You have collected the right bits of documentation. One note for Mac users - Motif on Mac works slowly with XFT, due to some interaction of XQuartz and core MacOS drawing subsystem. If you apply this patch to Motif, program with XFT will work at decent speed. http://bugs.motifzone.com/show_bug.cgi?id=1715

justinmeiners commented 2 years ago

With that information I would probably prefer to make the default aliased, and then provide the config file for those interested in changing it to anti-aliased (at least until the patch is included). Am I correctly reading that the report has gone untouched for over a year?

dpeterc commented 2 years ago

The "default" XFT rendering with Motif on MacOS is slow, but only for drawing labels. The rest of the software speed is normal. So it is not that dramatic. But opening menus is not snappy, and scrolling long lists is really slow. I think your program will not be terribly affected with XFT slowness, even if you use unpatched Motif. Try it for yourself and see.

As for the fact that my patch was not integrated and nobody bothered to reply or check it - it just shows that active Motif development has stopped. I have bugged ICS from time to time with pleas to fix some obvious bugs, which were reported with solution in bugzilla. A couple of times they did it, but now they don't even remove obvious spam from Bugzilla, which renders it almost useless. Bugzilla was also down for months and nobody seemed to bother.

justinmeiners commented 2 years ago

@dpeterc I submitted a note to ICS with a link to your issue on bugzilla for this. I am hoping that more than one of us can get something to happen.

justinmeiners commented 2 years ago

@dpeterc Here is what I got.

Screen Shot 2022-02-18 at 8 38 46 AM

My reading of this is "we don't like the way X11 was implemented on mac", which may be true, but I don't think is a good response. Frequent round trips to the Xserver are bad, even if they are worse on mac. Am I wrong? I am happy to reply to this.

Is there actually a bug we could go after in XQuartz?

One approach to getting the fix available for users is to apply the patch in the motif hombrew formula. Is this of interest to you?

dpeterc commented 2 years ago

@justinmeiners thank you Justin, for pushing for inclusion of this bug fix.

I will just point to the parts of ISC answers which are not correct in my opinion. The wording should be: "The bug is reported to be relevant to macOS or remote X connection only."

So it is still quite relevant, since Motif is one of the old toolkits, which still work perfectly over network, and people do use it that way. A lot of older scientific software is still Motif based, and MacOS usage in academia is high, now that classical Unix workstations are thing of the past.

RedHat has created a similar patch AND IT IS ALREADY INCLUDED in the latest Motif. Problem is, that it was not applied to all the cases, so it shows as slow performance on XmList widget with XFT fonts. Hence slow opening of Menus, or slow scrolling of textual lists (on MacOS or remote connection). The bug consists in the implementation of drawing of XmLabel, which queries background color from server, in order to draw antialiased text with XFT (for blending foreground and background colors during antialiasing). This query causes round trip from X Server, and this incurs the speed penalty (on MacOS with XQuartz or on remote connection). On Linux, it is not noticeable, because Xlib is more optimized. But it is still a bug, since any application, which floods the X Server with Xlib requests, which need round trip, are poorly written applications, with bad understanding of X11. To quote Wikipedia on X11:

_"X's design requires the clients and server to operate separately, and device independence and the separation of client and server incur overhead. Most of the overhead comes from network round-trip delay time between client and server (latency) rather than from the protocol itself: the best solutions to performance issues depend on efficient application design."_

And if library (Motif) does this mistake, then even carefully written Motif applications will have poor performance.

The corrections consists in simply caching the background color from last drawing of label (thus avoiding XQueryColor and round-trip), so repetitive drawing of XFT text on the same background color (which is the most typical case) becomes fast.

justinmeiners commented 2 years ago

@dpeterc I will relay the message. :)

justinmeiners commented 1 year ago

@dpeterc bugzilla on motif zone is dead. Can you post the patch here?

dpeterc commented 1 year ago

@justinmeiners

Download Motif from Sourceforge, edit XmRenderT.c and replace functions _XmXftDrawString2 and _XmXftDrawString. After the fix, all Motif user interface refreshes (which use XFT fonts) on Mac OS X will be faster. Here are the functions to replace:

void
_XmXftDrawString2(Display *display, Window window, GC gc, XftFont *font, int bpc,
#if NeedWidePrototypes
                int x, int y,
#else
                Position x, Position y,
#endif
                char *s, int len)
{
    XftDraw *draw = _XmXftDrawCreate(display, window);
    XGCValues gc_val;
    XftColor xftcol;

    XGetGCValues(display, gc, GCForeground, &gc_val);
#ifdef FIX_1536
    xftcol = _XmXftGetXftColor(display, gc_val.foreground);
#else
    XColor xcol;
    xcol.pixel = gc_val.foreground;
    XQueryColor(display, DefaultColormap(display,
        DefaultScreen(display)), &xcol);
    xftcol.color.red = xcol.red;
    xftcol.color.blue = xcol.blue;
    xftcol.color.green = xcol.green;
    xftcol.color.alpha = 0xFFFF;
#endif

    switch (bpc)
    {
case 1:
XftDrawStringUtf8(draw, &xftcol, font,
x, y, (XftChar8 *)s, len);
break;
case 2:
XftDrawString16(draw, &xftcol, font,
x, y, (XftChar16 *)s, len);
break;
case 4:
XftDrawString32(draw, &xftcol, font,
x, y, (XftChar32 *)s, len);
break;
default:
XmeWarning(NULL, "_XmXftDrawString(unsupported bpc)\n");
    }
}

void
_XmXftDrawString(Display *display, Window window, XmRendition rend, int bpc,
#if NeedWidePrototypes
                int x, int y,
#else
                Position x, Position y,
#endif
                char *s, int len,
#if NeedWidePrototypes
int image
#else
Boolean image
#endif
)
{
    XftDraw *draw = _XmXftDrawCreate(display, window);
    XftColor    fg_color = _XmRendXftFG(rend);

    if (image)
    {
        XftColor bg_color = _XmRendXftBG(rend);
XGlyphInfo ext;
ext.xOff = 0;

switch (bpc)
{
   case 1:
       XftTextExtentsUtf8(display, _XmRendXftFont(rend),
               (FcChar8*)s, len, &ext);
break;
   case 2:
       XftTextExtents16(display, _XmRendXftFont(rend),
                (FcChar16*)s, len, &ext);
break;
   case 4:
       XftTextExtents32(display, _XmRendXftFont(rend),
                (FcChar32*)s, len, &ext);
break;
}

if (_XmRendBG(rend) == XmUNSPECIFIED_PIXEL)
{
   XGCValues gc_val;

   XGetGCValues(display, _XmRendGC(rend), GCBackground, &gc_val);
#ifdef FIX_1536
   fg_color = _XmXftGetXftColor(display, gc_val.foreground);
#else
   XColor xcol;
   xcol.pixel = gc_val.background;
            XQueryColor(display, DefaultColormapOfScreen(
                  DefaultScreenOfDisplay(display)), &xcol);
   bg_color.pixel = xcol.pixel;
   bg_color.color.red = xcol.red;
   bg_color.color.green = xcol.green;
   bg_color.color.blue = xcol.blue;
   bg_color.color.alpha = 0xFFFF;
#endif
}
#ifdef FIX_1451
        XftDrawRect(draw, &bg_color, x, y - _XmRendXftFont(rend)->ascent,
           ext.xOff,
   _XmRendXftFont(rend)->ascent +
   _XmRendXftFont(rend)->descent);
#else
        XftDrawRect(draw, &bg_color, x - 10, y - _XmRendXftFont(rend)->ascent - 10,
           ext.xOff +20,
   _XmRendXftFont(rend)->ascent +
   _XmRendXftFont(rend)->descent + 20);
#endif
    }

    if (_XmRendFG(rend) == XmUNSPECIFIED_PIXEL)
    {
        XGCValues gc_val;
XGetGCValues(display, _XmRendGC(rend), GCForeground, &gc_val);
#ifdef FIX_1536
fg_color = _XmXftGetXftColor(display, gc_val.foreground);
#else
XColor xcol;
xcol.pixel = gc_val.foreground;
        XQueryColor(display, DefaultColormapOfScreen(
              DefaultScreenOfDisplay(display)), &xcol);
fg_color.pixel = xcol.pixel;
fg_color.color.red = xcol.red;
fg_color.color.green = xcol.green;
fg_color.color.blue = xcol.blue;
fg_color.color.alpha = 0xFFFF;
#endif
    }

    switch (bpc)
    {
case 1:
XftDrawStringUtf8(draw, &fg_color, _XmRendXftFont(rend),
x, y, (XftChar8 *)s, len);
break;
case 2:
XftDrawString16(draw, &fg_color, _XmRendXftFont(rend),
x, y, (XftChar16 *)s, len);
break;
case 4:
XftDrawString32(draw, &fg_color, _XmRendXftFont(rend),
x, y, (XftChar32 *)s, len);
break;
default:
XmeWarning(NULL, "_XmXftDrawString(unsupported bpc)\n");
    }
}

I also attach the complete replacement file, which contains some other small improvements and formatting fixes. XmRenderT.c.gz

justinmeiners commented 1 year ago

@dpeterc thanks. I'm trying to advocate for this again, either in motif or a patch for homebrew.

dpeterc commented 1 year ago

@justinmeiners I hope you will be successful. It would be even better if ICS would restore Motif bugzilla or transfer its contents to sourceforge, since it contained a lot of valuable historical information, which could help in further development (or custom bug fixes).

justinmeiners commented 1 week ago

I was thinking about this today. Here are notes for historical purposes.

This is a page about the patch made by Red hat to address the same XFT issue: https://access.redhat.com/errata/RHBA-2013:1484 Here we find RH bugzilla number: rhbz#1005742. Everywhere else on the internet refers to this number.

A search bring up a few RPM archives containing motif patch files. Here are two such repositories: https://rsync.rediris.es/mirror/slc/slc65/updates/i386/SRPMS/repoview/openmotif.html https://linuxsoft.cern.ch/cern/slc66/i386/yum/updates/repoview/openmotif-devel.html

This is the relevant patch: openmotif-2.3.3-motifzone_1536.patch

I'll also include a zip of all the other patches from the RPM: Archive.zip

Here is the changelog from sites above that describe what each patch does:

Changelog by Thomas Woerner (2016-10-31):- Added XmComboBox patch to properly set child args (rhbz#1208829)   (MotifZone bug #1473)
Changelog by Thomas Woerner (2014-06-13):- fixed Label size computed wrong within a Form (rhbz#869782) (rhbz#953938)   (copy of rhbz#980577)   (MotifZone bug #1612 final upstream patch with white space changes) - fixed segmentation violation in XmList after calling XmListDeleteAllItems    and clicking on a new item with left-shift left-button click (rhbz#1058644)   (MotifZone bug #1636)
Changelog by Thomas Woerner (2014-05-12):- added lost patch for #647411: openmotif-2.3.3-motifzone_1529.patch   (rhbz#1096754) - fixed missing outline in mwm while moving window (rhbz#1096749)   (copy of rhbz#997241)
Changelog by Thomas Woerner (2013-09-09):- fixed Performance issue: XmListSetPos() is very very slow (rhbz#1005742)   (MotifZone bug #1536)
Changelog by Thomas Woerner (2012-10-15):- fixed use after free with comboboxes and XIM (rhbz#866499)   (MotifZone bug #1559) - fixed border at insertion cursor if XmNmarginWidth is set (rhbz#866496)   (MotifZone bug #1552) - fixed copy/paste problem with Clipboard (rhbz#867463)   (MotifZone bug #1529)
Changelog by Thomas Woerner (2011-08-15):- fixed Label draws Xft text over border of its parent (rhbz#584300#c3)   (MotifZone bug #1521 refixed)
Changelog by Thomas Woerner (2016-10-31):
- Added XmComboBox patch to properly set child args (rhbz#1208829)
  (MotifZone bug #1473)
Changelog by Thomas Woerner (2014-06-13):
- fixed Label size computed wrong within a Form (rhbz#869782) (rhbz#953938)
  (copy of rhbz#980577)
  (MotifZone bug #1612 final upstream patch with white space changes)
- fixed segmentation violation in XmList after calling XmListDeleteAllItems 
  and clicking on a new item with left-shift left-button click (rhbz#1058644)
  (MotifZone bug #1636)
Changelog by Thomas Woerner (2014-05-12):
- added lost patch for #647411: openmotif-2.3.3-motifzone_1529.patch
  (rhbz#1096754)
- fixed missing outline in mwm while moving window (rhbz#1096749)
  (copy of rhbz#997241)
Changelog by Thomas Woerner (2013-09-09):
- fixed Performance issue: XmListSetPos() is very very slow (rhbz#1005742)
  (MotifZone bug #1536)
Changelog by Thomas Woerner (2012-10-15):
- fixed use after free with comboboxes and XIM (rhbz#866499)
  (MotifZone bug #1559)
- fixed border at insertion cursor if XmNmarginWidth is set (rhbz#866496)
  (MotifZone bug #1552)
- fixed copy/paste problem with Clipboard (rhbz#867463)
  (MotifZone bug #1529)
Changelog by Thomas Woerner (2011-08-15):
- fixed Label draws Xft text over border of its parent (rhbz#584300#c3)
  (MotifZone bug #1521 refixed)