GSoC 2024: Improvements to the Blender macOS User Interface Experience - Weekly Reports

Hello, I’m Jonas Holzman, and over this summer I’ll be working on improving the Blender macOS User Interface Experience.

Synopsis

In recent years, Blender support for macOS specific features has drastically improved. With the introduction of the Metal Viewport, features such as HDR support and development support from Apple, Blender can now be easily regarded as one of the best 3D applications available for the Mac. However, when it comes to its user interface, Blender still doesn’t feel quite properly integrated within the macOS environment. This GSoC proposal aims to change this, with the goal of making Blender feel closer to a fully native macOS application.

Benefits

This proposal plans to improve the Blender macOS user experience by incorporating part of the Blender interface into the macOS interface. Effectively making it closer to the macOS Human Interface Guidelines, and providing macOS Blender users with a familiar experience, more tightly integrated into their operating system.

To achieve this goal, this proposal will focus on the improvements of two main UI elements: the macOS menu bar and title bar. While this proposal will focus on macOS implementation, a byproduct of it will be the creation of an unified interface for native menu bar items, which will then make it possible to implement such functionality on other OSes and Desktop Environments in the future.

Visual Mockups / Proof of Concepts


You can find more details about the project and its deliverables in the project’s proposal.

In this thread, you will find the project’s weekly reports. Feel free to also share your thoughts and feedback in the project dedicated feedback thread.

5 Likes

We had a kickoff meeting for the project yesterday, here are the notes.


GSoC 2024: MacOS UI/UX improvements - Kickoff Meeting

Present: Jonas Holzman, Julian Eisel, Raul Fernandez

Why the project got accepted

  • Solid proposal, promising contributor
  • MacOS UI contributor/contributions needed generally
  • But: Objections against the proposed changes
    • Menu bar: We probably don’t want this at all
    • Title bar: Generally interesting, UI module would like to have an own title bar. But a lot of design questions to be answered.
  • Julian’s point: GSoC is explicitly not about getting cool features, but about getting contributors for open source development. There’s potential for longer term contributions besides the project (kinda: accept contributor more than the project).
  • So: Accepted project, but focus on client side decorations (CSD) / title bar:
    • Prototyping for title bar/ CSD
    • API design for controlling & drawing into title bar
    • If at the end we have good knowledge of how to implement custom title bars in Blender, that’s a great outcome. More is bonus.
  • Julian and Raul will mentor

Communication

  • Thomas: Development Coordinator
  • Public by default
  • Which chat channel to use? UI module? Separate channel? Check with Thomas
  • Weekly reports
  • Weekly sync up meetings

Process

  • As much as possible in main branch. Might be difficult bc of the nature of the project.
  • Expect regular commits, daily if possible. WIP changes allowed.
  • Single project PR, more PRs as useful/needed
  • It’s fine to work on other MacOS/UI improvements (e.g. refactoring Ghost Cocoa code). But focus shouldn’t derail too much.

Next Week(s) Planning

  • 1st two weeks: Prototyping & API research
  • Focus on biggest uncertainties (e.g. adding space to drag)

Potential Issues

  • Extending the topbar into window decorations
  • How to handle window buttons? Different position/size on different platform etc
  • How does macOS know we clicked on empty space for dragging the window? Is the event tagged as consumed? Can you add dragging hotspots? Something to investigate.
  • Window controls should remain interactive if Blender is frozen, avoid handling in own UI/window-manager code
  • Design: Windows without topbar? Preferences etc
  • Design: Where to place the file path, Blender version etc?
5 Likes

Week 1

May 27 - May 31

This week:

Code-wise, I wasn’t that productive this week as I ended up having to finish some personal work which should still take me up to around Tuesday, after which I’ll be more available to work on the project.

Next goals:

  • Proper handling of the topbar layout area rectangle (enabling proper padding, traffic light alignment, and more)
  • Differentiating between main blender windows and child/auxiliary windows to properly apply decorations
  • Starting to draft a proper macOS inline titlebar design, research and answer practical design questions (Filename placement, bar state during loading, etc…)
6 Likes

Week 2

June 3 - 7

This week:

  • Initial GHOST API for enabling/disabling per-window decorations
  • Apply decorations based off the presence of global areas (topbar/statusbar)
  • Researched and explored different ways of implementing custom titlebars decorations on macOS

Next Goals:

  • Implement dynamic topbar padding for inline titlebar
  • Custom Traffic Light (Close/Minimize/Maximize) button views for flexible placement
  • Compute the dragging area, padding and traffic light placement based on the topbar layout rectangle
  • Capture drag events directly within the main Blender content view, and use events to cancel drag on UI actions
  • Extend the GHOST decoration API to accommodate these objectives
3 Likes

Week 3

June 10 - 14

This week:

Next Goals:

  • Continue improving inline decorations with padding, proper dragging, etc… (see previous week’s goals)
  • Tidy up with the aim of releasing the client-side window decorations as an experimental feature
  • Start working on other macOS UX fix and features (Window Positioning bugs, iCloud integration, etc…)
9 Likes

Week 4

June 17 - 21

This Week:

Globally quite an unproductive week GSoC wise as I was busy with a personal project I couldn’t postpone from Thursday to Monday afternoon. However, starting tomorrow, I’ll have my entire week free to work on the project and catch back up.

Still, this week, I worked on non-inline titlebar macOS decoration for non-main windows (Preferences, popped-out editors, Render View, etc…) which I plan to release this week as a standalone PR along with a separate refactor PR of the Cocoa/Objective-C GHOST macOS layer.

Following that idea, I decided with my two mentors to postpone prototyping on the main inline window decoration task for now to focus on landing usable and finished macOS UI/UX deliverables for users to play with. And will thus next focus on fixing the macOS window sizing and placement bugs, and possibly work on globally improving window restoration, as was discussed in this PR.

Once that’s done, I will split my time between continuing work on inline window decorations (see previous reports), and working on other macOS UX deliverables, such as iCloud integration, improved text cursor behavior, better system interactions, maybe better app packaging using Universal Binaries, and if I have some additional time, some global UI papercuts improvements.

4 Likes

We do have a TODO about it, but it is aimed to be done as part of Steam packaging. Using universal binary for all other places has a downside of heavily increased download size. Which is especially unideal since the x86 macOS platforms seems to be on their way to be phased out.
I wouldn’t really prioritize this for the GSoC project.

Right yeah, I see what you mean, just to see, I did some quick tests to see what a universal binary build would cost us in terms of size. Here are the results on the latest commit from main (56fdfe5) using the default CMake Release config, with the universal binary created using lipo.

Binary Size
arm64 156,4 MB
x86_64 170,9 MB
Universal 327,3 MB

This does make for an increase in binary size of 109%, effectively doubling it, as the two binaries are really just appended to each others, however, when we look at the total macOS app bundle size, we get:

.app Bundle Size
arm64 812 MB
x86_64 866,8 MB
Universal 982,9 MB

Which gives us an increase of 21% from arm64 to Universal, which is still consequential, but has already way less of an impact on the total download size.

For me, the eventual rational for shipping Blender as an universal binary, like other FOSS softwares do, such as Godot, is less about guaranteeing multi-arch support, and more about making sure users don’t accidentally run Blender through Rosetta, thus lowering their performances, a problem I already ran into myself in the past after copying Blender builds between macs, and keeping old DMGs around. Especially since there’s no way of realizing that you’re actually running Blender through emulation, unless you inspect the application or use an external indicator like Silicon Info.

This situation might even actually degrade with time, as Intel Macs become more rare, Blender will still need to keep shipping x86_64 builds for as long as they’re officially supported, as such, the number of users potentially using the wrong builds and lowering their performances might actually increase with time. Although this can of course also be solved through clear Download guidelines, or eventually some sort of splash screen indicator that Blender is currently being run under Rosetta, using an Universal Binary might be a simpler solution.

On the technical side of things, CMake does most of the heavy lifting for us, to build an x86_64 binary on arm64, just setting the CMAKE_OSX_ARCHITECTURE=x86_64 build flag is enough, along with manually enabling the lib/macos_x64 submodule. Ideally, we’d want CMake to be able to perform the lipo concatenation itself using CMAKE_OSX_ARCHITECTURES=arm64;x86_64, which currently fails due to the library directory search not expecting multiple architectures, but I might dig a bit more into it later to see if that’s easily fixable.

As you said, this is certainly not an obvious tradeoff, and would certainly require more discussion with the Platform module, but all in all, it might be worth it as a way to globally make things simpler, guaranteeing good performances and simplifying release builds creation and distribution, especially considering that the end download size increase is not that consequential.

If you want to continue this discussion, feel free to either reply here or ping me on blender.chat if you prefer to not pollute this thread too much, I can also create another devtalk topic if you’d think that’s more appropriate.

Did you consider the .dylib and .so (Python module) files? I would have expected those to add another 400MB - 500MB.

Ah… Good point you’re right, indeed I didn’t factor in the rest of the executable libs that needs to be turned into universal binaries, as I just based myself off the existing arm64 bundle to quickly throw something together (which of course only worked on my machine, doing the same thing using the x86_64 bundle would cause a crash due to missing libs).

I took a stab at trying to properly generate Universal App Bundles for macOS. For this to work, all used libraries need to be concatenated using lipo just like the Blender executable itself. As a quick experiment, I wrote a simple Python script that creates the universal libraries by merging the lib/macos_arm64 and lib/macos_x64 directories into a lib/macos_universal directory, using lipo if the file is an executable or static/dynamic lib, recreating relative symlinks, and simply copying every other files, which I then fed into CMake.

After disabling SDL due to a weird Objective-C relate linker error I didn’t want to completely investigate, and running into a few linker warnings (which seems to be a known issue that’s fixed when using XCode as a generator) the result is a pretty staggering… 1.52GB Universal app bundle :confused:

Updated Table

.app Bundle Size
arm64 812 MB
x86_64 866,8 MB
Universal 1.52 GB

As the resulting bundle basically doubles the download size, the whole idea of using these for Blender releases kinds of fall through. Still, I’ll probably turn the script and slight CMake modifications I made into a proof of concept PR for anyone who wants to experiment with this or want to be able to build a Universal Binary version of Blender for themselves (and eventually also as a base solution for the TODO PR @sergey mentioned). As a future side-task, I might also experiment with displaying a splash screen warning if Blender is being run through Rosetta to still address the problem I talked about above.

The way Steam delivery currently works is that it downloads builds from buildbot, repackages, and pushes them to steam. It does not do compilation. If we can have a script to which you can give two builds of Blender (x86 and arm64) that’d make it easy to attach it to the current pipeline. Do you think it is possible (it actually sounds you have similar script already)?

Ah right I see, yeah for sure that should be possible. The script I made merges two pre-compiled library directories together so that they can be used to compile a Universal Binary, but I should be able to adapt it for it to take two x86_64 and arm64 Blender app bundles instead for this to be done post-compilation.

It even somewhat simplifies things as we don’t have to deal with library symlinks and merging static libraries together to please the compiler, just merging the Blender executable and embedded dynamic libraries inside the bundle should be enough. I’ll modify the script in that sense, would you like me to drop it here once it’s done or do you prefer me opening a PR somewhere?

I think you can create a PR against the blender-devops. Maybe place it under blender-devops/buildbot/worker/blender. I forgot how exactly the Steam re-packaging work, but it seems it already does unpacking of DMG. Perhaps this could simplify some work for you. The details of that part are in the blender-devops/buildbot/worker/deploy/steam.py. Ideally we download both DMGs and call a function from your script.

Unless you want to dig into more details of this devops pipeline, you can provide script which you think will lets us do an universal build, and then we do the devops pipeline side of the changes.