• Major update to the macOS port of Tk

    From steve@steve@digitalsmarties.com (stevel) to comp.lang.tcl on Thu Jul 4 11:53:11 2024
    From Newsgroup: comp.lang.tcl

    Posted on behalf of Marc Culler, there is a major update to the macOS
    port of Tk available for testing.

    ---

    Tk Timeline watchers may have noticed a long chain of commits to the cgimage_with_crossing branch over the last month.  This announcement is
    to explain what has been going on there.  In brief, that branch contains
    a major change to how drawing works in the macOS port of Tk.  This
    change makes drawing in the macOS port work in a way which is much
    closer to how it works in the other platforms, and much closer to what
    the generic Tk code expects. The result is better performance and
    increased stability.

    The work is based on an idea of Christopher Chavez's.  He realized that Apple's Appkit design allowed for an alternative drawing strategy, and
    wrote a proof-of-concept implementation.  I had created a branch
    containing his implementation a couple of years ago.  Recently I (Marc)
    merged that branch with Tk 9 and then spent a few weeks ironing out
    wrinkles.  Nicolas Bats, Torsten Berg, Steve Landers, and Kevin Walzer
    kindly offered to help me by testing the new implementation on their
    apps, some of which provide very challenging environments for Tk.  The
    result of this work is in the cgimage-with-crossing branch.  (The branch
    also includes a fix for ticket [22349fc78a] which is about <Enter> and
    <Leave> events - hence the reference to crossing in the branch tag.)

    The five of us are confident that this is a significant improvement.
    Some highlights are:
        * Better performance - CPU-intensive apps use about 20% fewer CPU
    cycles
        * Better conformance - Most runs of the regression test suite on
    macOS 14 show no failures.  This is not close to being the case for the
    trunk branch.
        * Fewer graphical artifacts (and work continues on those that
    remain.)
        * Fewer crashes (none that we know of at the moment.)

    Given that the branch has been tested on large and complex apps - all of
    which are working well - this is a major step forwards and we’d like to
    see it tested more widely.  To that end, although we are late in the
    release cycle we are comfortable recommending that this be merged into
    trunk and made part of beta3.  That’s the only way we can guarantee
    wider testing. Of course, if any issues crop up they will be addressed
    in a timely manner.  If you are a macOS tkchat user please download and
    try https://www.codebykevin.com/TkChat_Setup_1.5.2.dmg   If you want to
    try the new macOS Tk with your own code and are comfortable building it yourself please checkout and build the Tk cgimage_with_crossing branch

    The rest of this message gives some more details about the changes.

    The main difference is that the new drawing strategy does away with the asynchronous drawing via the drawRect method.  A macOS app which uses
    drawRect is supposed to do all of its drawing within the drawRect
    method, which can only be called by the NSApplication object.  The app
    can request that drawRect be called by setting the viewNeedsDisplay
    flag, but can not call drawRect.  The original design of the macOS Aqua
    port only partially complied with this strategy.  In fact it was
    possible to obtain a valid graphics context for drawing to the backing
    layer of a window's contentView even outside of the drawRect method. 
    The original port would do this, e.g. in a widget display proc which is
    being run as an idle task.  But it would also draw in the drawRect
    method by first generating expose events for all widgets that need
    updates, then processing those expose events to create idle tasks, then processing all of those idle tasks immediately.

    Obviously this scheme was not what Tk expected.  Nor was it what Apple expected.  And Apple put an abrupqt end to half of it with the release
    of macOS Mojave, which made it impossible to obtain a valid graphics
    context outside of the drawRect method. When Tk was first built on
    Mojave, it produced nothing but totally black windows.  Eventually this
    was worked around by arranging that any drawing operation which failed
    due to an invalid graphics context would be rescheduled and also to
    modify drawRect to make it (attempt to) run all of those rescheduled
    idle tasks.

    With the new macOS code it is once again true that Tk always has a valid graphics context available and hence can draw at any time.  It draws
    into a CGBitmapImageContext which serves as the backing store for a Tk Window.  Instead of calling drawRect, it is configured with Apple's
    other option which is to call updateLayer instead.  In the new setup updateLayer installs the CGImage as the CALayer of the ContentView of
    the NSWindow which hosts the Tk toplevel, causing the contents of the
    image to appear in the window.  It also creates a new CGImage containing
    a copy of the window in which subsequent drawing operations take place. 
    This allows drawing operations to take place at the expected time and in
    the expected order.  That makes for better stability and less unpredictability.  In addition, it removes the overhead that arises from attempting a drawing operation, having it fail due to an invalid
    graphics context, rescheduling and rerunning the operation.  This
    accounts for the reduced CPU usage.

    - Marc
    --- Synchronet 3.20a-Linux NewsLink 1.114