// Copyright Epic Games, Inc. All Rights Reserved. #include "SlateViewerApp.h" #include "RequiredProgramMainCPPInclude.h" #include "Widgets/Testing/STestSuite.h" #include "Widgets/Testing/SStarshipSuite.h" #include "ISourceCodeAccessModule.h" #include "Widgets/Testing/SPerfSuite.h" #include "Widgets/Docking/SDockTab.h" #include "SWebBrowser.h" #include "Framework/Application/SlateApplication.h" #include "IWebBrowserWindow.h" #include "IWebBrowserPopupFeatures.h" #include "Stats/StatsSystem.h" #include "WebBrowserModule.h" #include "Styling/StarshipCoreStyle.h" IMPLEMENT_APPLICATION(SlateViewer, "SlateViewer"); #define LOCTEXT_NAMESPACE "SlateViewer" namespace WorkspaceMenu { TSharedRef DeveloperMenu = FWorkspaceItem::NewGroup(LOCTEXT("DeveloperMenu", "Developer")); } int RunSlateViewer( const TCHAR* CommandLine ) { FTaskTagScope TaskTagScope(ETaskTag::EGameThread); // start up the main loop GEngineLoop.PreInit(CommandLine); // Make sure all UObject classes are registered and default properties have been initialized ProcessNewlyLoadedUObjects(); // Tell the module manager it may now process newly-loaded UObjects when new C++ modules are loaded FModuleManager::Get().StartProcessingNewlyLoadedObjects(); // crank up a normal Slate application using the platform's standalone renderer FSlateApplication::InitializeAsStandaloneApplication(GetStandardStandaloneRenderer()); FSlateApplication::InitHighDPI(true); // Load the source code access module ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked( FName( "SourceCodeAccess" ) ); // Manually load in the source code access plugins, as standalone programs don't currently support plugins. #if PLATFORM_MAC IModuleInterface& XCodeSourceCodeAccessModule = FModuleManager::LoadModuleChecked( FName( "XCodeSourceCodeAccess" ) ); SourceCodeAccessModule.SetAccessor(FName("XCodeSourceCodeAccess")); #elif PLATFORM_WINDOWS IModuleInterface& VisualStudioSourceCodeAccessModule = FModuleManager::LoadModuleChecked( FName( "VisualStudioSourceCodeAccess" ) ); SourceCodeAccessModule.SetAccessor(FName("VisualStudioSourceCodeAccess")); #endif // set the application name FGlobalTabmanager::Get()->SetApplicationTitle(LOCTEXT("AppTitle", "Slate Viewer")); FModuleManager::LoadModuleChecked("SlateReflector").RegisterTabSpawner(WorkspaceMenu::DeveloperMenu); FGlobalTabmanager::Get()->RegisterNomadTabSpawner("WebBrowserTab", FOnSpawnTab::CreateStatic(&SpawnWebBrowserTab)) .SetDisplayName(LOCTEXT("WebBrowserTab", "Web Browser")); if (FParse::Param(FCommandLine::Get(), TEXT("perftest"))) { // Bring up perf test SummonPerfTestSuite(); } else { FGlobalTabmanager::Get()->SetApplicationTitle(LOCTEXT("AppTitleStarship", "Starship Slate Viewer")); FAppStyle::SetAppStyleSetName(FStarshipCoreStyle::GetCoreStyle().GetStyleSetName()); RestoreStarshipSuite(); if (FParse::Param(FCommandLine::Get(), TEXT("testsuite"))) { RestoreSlateTestSuite(); } } #if WITH_SHARED_POINTER_TESTS SharedPointerTesting::TestSharedPointer(); SharedPointerTesting::TestSharedPointer(); #endif // initialize the web browser FWebBrowserInitSettings BrowserInitSettings = FWebBrowserInitSettings(); IWebBrowserModule::Get().CustomInitialize(BrowserInitSettings); // loop while the server does the rest while (!IsEngineExitRequested()) { BeginExitIfRequested(); FTaskGraphInterface::Get().ProcessThreadUntilIdle(ENamedThreads::GameThread); UE::Stats::FStats::AdvanceFrame(false); FTSTicker::GetCoreTicker().Tick(FApp::GetDeltaTime()); FSlateApplication::Get().PumpMessages(); FSlateApplication::Get().Tick(); FPlatformProcess::Sleep(0.01); GFrameCounter++; } FCoreDelegates::OnExit.Broadcast(); FSlateApplication::Shutdown(); FModuleManager::Get().UnloadModulesAtShutdown(); GEngineLoop.AppPreExit(); GEngineLoop.AppExit(); return 0; } namespace { TMap, TWeakPtr> BrowserWindowWidgets; bool HandleBeforePopup(FString Url, FString Target) { return false; // Allow any popup } bool HandleBrowserCloseWindow(const TWeakPtr& BrowserWindowPtr) { TSharedPtr BrowserWindow = BrowserWindowPtr.Pin(); if(BrowserWindow.IsValid()) { if(!BrowserWindow->IsClosing()) { // If the browser is not set to close, we tell the browser to close which will call back into this handler function. BrowserWindow->CloseBrowser(false); } else { const TWeakPtr* FoundBrowserWindowWidgetPtr = BrowserWindowWidgets.Find(BrowserWindow); if(FoundBrowserWindowWidgetPtr != nullptr) { TSharedPtr FoundBrowserWindowWidget = FoundBrowserWindowWidgetPtr->Pin(); if(FoundBrowserWindowWidget.IsValid()) { FoundBrowserWindowWidget->RequestDestroyWindow(); } BrowserWindowWidgets.Remove(BrowserWindow); return true; } } } return false; } bool HandleBrowserCreateWindow(const TWeakPtr& NewBrowserWindow, const TWeakPtr& PopupFeatures, TSharedPtr ParentWindow) { if(ParentWindow.IsValid()) { TSharedPtr PopupFeaturesSP = PopupFeatures.Pin(); check(PopupFeatures.IsValid()) const int PosX = PopupFeaturesSP->IsXSet() ? PopupFeaturesSP->GetX() : 100; const int PosY = PopupFeaturesSP->IsYSet() ? PopupFeaturesSP->GetY() : 100; const FVector2D BrowserWindowPosition(PosX, PosY); const int Width = PopupFeaturesSP->IsWidthSet() ? PopupFeaturesSP->GetWidth() : 800; const int Height = PopupFeaturesSP->IsHeightSet() ? PopupFeaturesSP->GetHeight() : 600; const FVector2D BrowserWindowSize(Width, Height); const ESizingRule SizeingRule = PopupFeaturesSP->IsResizable() ? ESizingRule::UserSized : ESizingRule::FixedSize; TSharedPtr NewBrowserWindowSP = NewBrowserWindow.Pin(); check(NewBrowserWindowSP.IsValid()) TSharedRef BrowserWindowWidget = SNew(SWindow) .Title(LOCTEXT("WebBrowserWindow_Title", "Web Browser")) .ClientSize(BrowserWindowSize) .ScreenPosition(BrowserWindowPosition) .AutoCenter(EAutoCenter::None) .SizingRule(SizeingRule) .SupportsMaximize(SizeingRule != ESizingRule::FixedSize) .SupportsMinimize(SizeingRule != ESizingRule::FixedSize) .HasCloseButton(true) .IsInitiallyMaximized(PopupFeaturesSP->IsFullscreen()) .LayoutBorder(FMargin(0)); // Setup browser widget. TSharedPtr BrowserWidget; { TSharedPtr Contents; BrowserWindowWidget->SetContent( SNew(SBorder) .VAlign(VAlign_Fill) .HAlign(HAlign_Fill) .Padding(0) [ SAssignNew(Contents, SVerticalBox) ]); Contents->AddSlot() [ SAssignNew(BrowserWidget, SWebBrowser, NewBrowserWindowSP) .ShowControls(PopupFeaturesSP->IsToolBarVisible()) .ShowAddressBar(PopupFeaturesSP->IsLocationBarVisible()) .OnCreateWindow(FOnCreateWindowDelegate::CreateStatic(&HandleBrowserCreateWindow, ParentWindow)) .OnCloseWindow(FOnCloseWindowDelegate::CreateStatic(&HandleBrowserCloseWindow)) ]; } // Setup some OnClose stuff. { struct FLocal { static void RequestDestroyWindowOverride(const TSharedRef& Window, TWeakPtr BrowserWindowPtr) { TSharedPtr BrowserWindow = BrowserWindowPtr.Pin(); if(BrowserWindow.IsValid()) { if(BrowserWindow->IsClosing()) { FSlateApplicationBase::Get().RequestDestroyWindow(Window); } else { // Notify the browser window that we would like to close it. On the CEF side, this will // result in a call to FWebBrowserHandler::DoClose only if the JavaScript onbeforeunload // event handler allows it. BrowserWindow->CloseBrowser(false); } } } }; BrowserWindowWidget->SetRequestDestroyWindowOverride(FRequestDestroyWindowOverride::CreateStatic(&FLocal::RequestDestroyWindowOverride, TWeakPtr(NewBrowserWindow))); } FSlateApplication::Get().AddWindowAsNativeChild(BrowserWindowWidget, ParentWindow.ToSharedRef()); BrowserWindowWidget->BringToFront(); FSlateApplication::Get().SetKeyboardFocus( BrowserWidget, EFocusCause::SetDirectly ); BrowserWindowWidgets.Add(NewBrowserWindow, BrowserWindowWidget); return true; } return false; } } TSharedRef SpawnWebBrowserTab(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(LOCTEXT("WebBrowserTab", "Web Browser")) .ToolTipText(LOCTEXT("WebBrowserTabToolTip", "Switches to the Web Browser to test its features.")) .TabRole(ETabRole::NomadTab) [ SNew(SWebBrowser) .OnCreateWindow(FOnCreateWindowDelegate::CreateStatic(&HandleBrowserCreateWindow, Args.GetOwnerWindow())) .OnCloseWindow(FOnCloseWindowDelegate::CreateStatic(&HandleBrowserCloseWindow)) .ParentWindow(Args.GetOwnerWindow()) ]; } #undef LOCTEXT_NAMESPACE