Merge branch 'develop' into feature/eterm-worker

This commit is contained in:
Martín Lucas Golini
2026-09-01 13:23:13 -03:00
11 changed files with 836 additions and 304 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -495,6 +495,13 @@ struct NativeMenuSource {
- (void)menuItemActivated:(NSMenuItem*)sender {
eeASSERT( [NSThread isMainThread] );
// Shortcut text on UIMenuItem is presentation-only; applications register the actual shortcut
// with their KeyBindings target. AppKit also invokes this action for native key equivalents,
// while SDL still forwards the same key-down event to eepp. Let the normal keybinding dispatch
// own keyboard activation so commands are not executed twice, while preserving menu clicks.
NSEvent* event = [NSApp currentEvent];
if ( nil != event && event.type == NSEventTypeKeyDown )
return;
auto found = _itemMap.find( sender );
if ( found != _itemMap.end() && nullptr != found->second )
found->second->activate();

View File

@@ -33,6 +33,17 @@ void ClipboardSDL::setText( const std::string& text ) {
#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN
sContent = text;
emscripten_browser_clipboard::copy( text );
#elif EE_PLATFORM == EE_PLATFORM_WIN
// SDL2's Windows backend retries reads when another process owns the clipboard, but not
// writes. Clipboard ownership is transient, so mirror the read-side retry policy here.
static constexpr int MAX_ATTEMPTS = 3;
for ( int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt ) {
if ( SDL_SetClipboardText( text.c_str() ) == 0 )
return;
if ( attempt + 1 < MAX_ATTEMPTS )
SDL_Delay( 10 );
}
Log::warning( "Failed to set clipboard text: %s", SDL_GetError() );
#else
SDL_SetClipboardText( text.c_str() );
#endif

View File

@@ -84,7 +84,8 @@ UTEST( FontRendering, glyphAdvanceDoesNotCreateTexturePages ) {
UTEST( FontRendering, subpixelCoverageCompositesPerChannel ) {
UIApplication app(
WindowSettings( 360, 220, "eepp - Subpixel Text Test", WindowStyle::Default,
WindowBackend::Default, 32 ),
WindowBackend::Default, 32, std::string(), 1, EE_SCREEN_KEYBOARD_ENABLED,
true ),
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
ResourceScope& scope = *app.getUI()->getResourceScope();
FontTrueTypePtr font = FontTrueType::New( "SubpixelText-Regular", scope );
@@ -228,7 +229,8 @@ UTEST( FontRendering, subpixelCoverageAllRenderers ) {
UTEST( FontRendering, scaledSubpixelGlyphAtlas ) {
UIApplication app(
WindowSettings( 256, 64, "eepp - Scaled Subpixel Glyph Atlas", VisualTestWindowStyle,
WindowBackend::Default, 32 ),
WindowBackend::Default, 32, std::string(), 1, EE_SCREEN_KEYBOARD_ENABLED,
true ),
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
ResourceScope& scope = *app.getUI()->getResourceScope();
FontTrueTypePtr font = FontTrueType::New( "ScaledSubpixelNonicons", scope );

View File

@@ -70,9 +70,13 @@ UTEST( SystemFontResolver, workerWarmUp ) {
warmUpThread.wait();
EXPECT_FALSE( resolver->isLoading() );
#if EE_PLATFORM == EE_PLATFORM_LINUX || EE_PLATFORM == EE_PLATFORM_BSD || \
EE_PLATFORM == EE_PLATFORM_WIN || EE_PLATFORM == EE_PLATFORM_MACOS || \
EE_PLATFORM == EE_PLATFORM_IOS || EE_PLATFORM == EE_PLATFORM_HAIKU
#if EE_PLATFORM == EE_PLATFORM_WIN || EE_PLATFORM == EE_PLATFORM_MACOS || \
EE_PLATFORM == EE_PLATFORM_IOS || EE_PLATFORM == EE_PLATFORM_LINUX || \
EE_PLATFORM == EE_PLATFORM_BSD || EE_PLATFORM == EE_PLATFORM_HAIKU
EXPECT_FALSE( resolver->isFontListPopulated() );
EXPECT_FALSE( resolver->resolveGeneric( GenericFamily::SansSerif, FontWeight::Normal, false )
.path.empty() );
#elif EE_PLATFORM == EE_PLATFORM_ANDROID
EXPECT_FALSE( resolver->enumerate().empty() );
#endif
@@ -80,6 +84,40 @@ UTEST( SystemFontResolver, workerWarmUp ) {
SystemFontResolver::destroySingleton();
}
#if EE_PLATFORM == EE_PLATFORM_WIN || EE_PLATFORM == EE_PLATFORM_MACOS || \
EE_PLATFORM == EE_PLATFORM_IOS || EE_PLATFORM == EE_PLATFORM_LINUX || \
EE_PLATFORM == EE_PLATFORM_BSD || EE_PLATFORM == EE_PLATFORM_HAIKU
UTEST( SystemFontResolver, nativeRenderingDoesNotEnumerate ) {
SystemFontResolver::setEnabled( true );
auto* resolver = SystemFontResolver::instance();
resolver->invalidateCache();
resolver->warmUp();
EXPECT_FALSE( resolver->isFontListPopulated() );
FontDesc sans = resolver->resolveGeneric( GenericFamily::SansSerif, FontWeight::Normal, false );
EXPECT_FALSE( sans.path.empty() );
FontQuery query;
query.family = sans.family;
EXPECT_FALSE( resolver->resolve( query ).path.empty() );
EXPECT_FALSE( resolver->resolveGeneric( GenericFamily::Monospace, FontWeight::Normal, false )
.path.empty() );
#if EE_PLATFORM == EE_PLATFORM_MACOS || EE_PLATFORM == EE_PLATFORM_IOS
EXPECT_FALSE(
resolver->getFallbackForCodepoint( 0x65E5, FontWeight::Normal, false ).path.empty() );
#else
resolver->getFallbackForCodepoint( 0x65E5, FontWeight::Normal, false );
#endif
EXPECT_FALSE( resolver->isFontListPopulated() );
EXPECT_FALSE( resolver->enumerate().empty() );
EXPECT_TRUE( resolver->isFontListPopulated() );
SystemFontResolver::setEnabled( false );
SystemFontResolver::destroySingleton();
}
#endif
UTEST( SystemFontResolver, fallbackWaitsForConcurrentWarmUp ) {
SystemFontResolver::setEnabled( true );
auto* resolver = SystemFontResolver::instance();

View File

@@ -2,7 +2,6 @@
#include <eepp/ui/doc/syntaxdefinitionmanager.hpp>
#include <eepp/ui/tools/uimergeview.hpp>
#include <eepp/ui/uiapplication.hpp>
#include <eepp/window/clipboard.hpp>
using namespace EE;
using namespace EE::UI;
@@ -82,9 +81,12 @@ UTEST( UIMergeView, UsesSharedResultDocumentAndAcceptIsUndoable ) {
EXPECT_TRUE( view->isToolbarVisible() );
EXPECT_TRUE( view->hasCommand( "merge-accept-left" ) );
auto* leftEditor = view->getLeftEditor();
leftEditor->getDocument().setSelection( { { 0, 0 }, { 0, 4 } } );
leftEditor->getDocument().execute( "copy", leftEditor );
EXPECT_STREQ( "left", app.getWindow()->getClipboard()->getText().c_str() );
auto& leftDocument = leftEditor->getDocument();
// Keep this hermetic: the Windows system clipboard can be temporarily owned by another
// process. The regression is that replacement side documents must retain the copy command.
EXPECT_TRUE( leftDocument.hasCommand( "copy" ) );
leftDocument.setSelection( { { 0, 0 }, { 0, 4 } } );
EXPECT_TRUE( leftDocument.getAllSelectedText() == "left" );
view->setToolbarVisible( false );
EXPECT_FALSE( view->isToolbarVisible() );
view->setToolbarVisible( true );

View File

@@ -245,7 +245,8 @@ void SettingsMenu::createSettingsMenu( App* app, UIMenuBar* menuBar ) {
const auto onMenuShowEvent = [this, menuHint]( UIPopUpMenu* menu, UIWidget* menuButton,
Uint32 menuBarIndex ) {
menu->on( Event::OnMenuShow, [this, menuButton, menuBarIndex, menu, menuHint]( auto ) {
if ( menuBarIndex == 0 && !mApp->isAnyStatusBarSectionVisible() )
if ( menuBarIndex == 0 && !mMenuBar->isGlobalMenuBarEnabled() &&
!mApp->isAnyStatusBarSectionVisible() )
menuHint->setVisible( true );
menu->setOwnerNode( mApp->getConfig().ui.showMenuBar
? mMenuBar->getButton( menuBarIndex )->asType<UIWidget>()