r.FullScreenMode

r.FullScreenMode

#Overview

name: r.FullScreenMode

This variable is created as a Console Variable (cvar).

It is referenced in 8 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.FullScreenMode is to define how the game handles full screen mode when requested. This setting variable is primarily used for controlling the rendering and display behavior of the game.

The r.FullScreenMode variable is utilized by the Unreal Engine’s rendering system and the core application framework. It’s referenced in various subsystems, including:

  1. The Console Manager (ConsoleManager.cpp)
  2. The Application Core module (CocoaWindow.cpp for Mac)
  3. The Engine module (GameUserSettings and GameEngine)
  4. The Game Viewport Client

The value of this variable is set through multiple means:

  1. Initially defined as a console variable with a default value of 1.
  2. Can be modified via command line options, INI files, or in-game settings.
  3. The GameUserSettings class can update this value based on user preferences.

This variable interacts with other window mode and display-related variables, such as the WindowMode enum and various resolution settings.

Developers should be aware of the following:

  1. The variable accepts three main values:
    • 0: Normal full screen (faster rendering, more vsync control, less GPU memory, potential 10-bit color)
    • 1: Windowed full screen (quick switching between apps and window mode, slight performance loss)
    • Any other number behaves like 0
  2. The setting may behave differently on different platforms (e.g., special handling for Windows D3D11/D3D12)
  3. In the editor, it always uses WindowedFullscreen mode to prevent issues

Best practices when using this variable include:

  1. Consider platform-specific behaviors when setting this value
  2. Use the GameUserSettings class to manage this setting for consistent user experience
  3. Be aware of the performance and visual quality trade-offs between different full screen modes
  4. Test thoroughly on all target platforms to ensure correct behavior

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp:3660

Scope: file

Source code excerpt:


static TAutoConsoleVariable<int32> CVarFullscreenMode(
	TEXT("r.FullScreenMode"),
	1,
	TEXT("Defines how we do full screen when requested (e.g. command line option -fullscreen or in ini [SystemSettings] fullscreen=true)\n"
		 " 0: normal full screen (renders faster, more control over vsync, less GPU memory, 10bit color if possible)\n"
		 " 1: windowed full screen (quick switch between applications and window mode, slight performance loss)\n"
		 " any other number behaves like 0"),
	ECVF_Scalability);

#Loc: <Workspace>/Engine/Source/Runtime/ApplicationCore/Private/Mac/CocoaWindow.cpp:214

Scope: file

Source code excerpt:

	{
		// Use the current default fullscreen mode when switching via the OS button
		static auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.FullScreenMode"));
		check(CVar);
		self.TargetWindowMode = CVar->GetValueOnAnyThread() == 0 ? EWindowMode::Fullscreen : EWindowMode::WindowedFullscreen;
		
#if WITH_EDITORONLY_DATA // Always use WindowedFullscreen for the Editor or bad things happen
		if (GIsEditor)
		{
			self.TargetWindowMode = EWindowMode::WindowedFullscreen;
		}
#endif
	}
}

- (void)windowDidEnterFullScreen:(NSNotification*)Notification
{
	WindowMode = self.TargetWindowMode;

	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
}

- (void)windowWillExitFullScreen:(NSNotification *)Notification
{
	FMacCursor* MacCursor = MacApplication ? (FMacCursor*)MacApplication->Cursor.Get() : nullptr;
	if (MacCursor)
	{
		MacCursor->SetShouldIgnoreLocking(true);
	}

	if (self.TargetWindowMode != EWindowMode::Windowed)
	{
		self.TargetWindowMode = EWindowMode::Windowed;
	}
}

- (void)windowDidExitFullScreen:(NSNotification*)Notification
{
	WindowMode = EWindowMode::Windowed;
	self.TargetWindowMode = EWindowMode::Windowed;

	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
}

- (void)windowDidBecomeMain:(NSNotification*)Notification
{
	SCOPED_AUTORELEASE_POOL;
	if ([NSApp isHidden] == NO)
	{
		[self orderFrontAndMakeMain:false andKey:false];
	}

	if (MacApplication)
	{
		GameThreadCall(^{
			if (MacApplication) // Another check because game thread may destroy MacApplication before it gets here
			{
				TSharedPtr<FMacWindow> Window = MacApplication->FindWindowByNSWindow(self);
				if (Window.IsValid())
				{
					MacApplication->OnWindowActivationChanged(Window.ToSharedRef(), EWindowActivation::Activate);
				}
			}
		}, @[ NSDefaultRunLoopMode, UnrealResizeEventMode, UnrealShowEventMode, UnrealFullscreenEventMode, UnrealCloseEventMode ], true);
	}
}

- (void)windowDidResignMain:(NSNotification*)Notification
{
	SCOPED_AUTORELEASE_POOL;
	[self setMovable: YES];
	[self setMovableByWindowBackground: NO];

	if (MacApplication)
	{
		GameThreadCall(^{
			if (MacApplication) // Another check because game thread may destroy MacApplication before it gets here
			{
				TSharedPtr<FMacWindow> Window = MacApplication->FindWindowByNSWindow(self);
				if (Window.IsValid())
				{
					MacApplication->OnWindowActivationChanged(Window.ToSharedRef(), EWindowActivation::Deactivate);
				}
			}
		}, @[ NSDefaultRunLoopMode, UnrealResizeEventMode, UnrealShowEventMode, UnrealFullscreenEventMode, UnrealCloseEventMode ], true);
	}
}

- (void)windowWillMove:(NSNotification*)Notification
{
	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
}

- (void)windowDidMove:(NSNotification*)Notification
{
	SCOPED_AUTORELEASE_POOL;
	bZoomed = [self isZoomed];
	
	NSView* OpenGLView = [self openGLView];
	[[NSNotificationCenter defaultCenter] postNotificationName:NSViewFrameDidChangeNotification object:OpenGLView];
	[[NSNotificationCenter defaultCenter] postNotificationName:NSViewBoundsDidChangeNotification object:OpenGLView];

	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
}

- (NSRect)constrainFrameRect:(NSRect)FrameRect toScreen:(NSScreen*)Screen
{
	NSRect ConstrainedRect = [super constrainFrameRect:FrameRect toScreen:Screen];

	if (self.TargetWindowMode == EWindowMode::Windowed)
	{
		// In windowed mode do not limit the window size to screen size
		ConstrainedRect.origin.y -= FrameRect.size.height - ConstrainedRect.size.height;
		ConstrainedRect.size = FrameRect.size;
	}

	return ConstrainedRect;
}

- (void)windowDidChangeScreen:(NSNotification*)Notification
{
	// The windowdidChangeScreen notification only comes after you finish dragging.
	// It does however, work fine for handling display arrangement changes that cause a window to go offscreen.
	if (bDisplayReconfiguring)
	{
		SCOPED_AUTORELEASE_POOL;
		NSScreen* Screen = [self screen];
		NSRect Frame = [self frame];
		NSRect VisibleFrame = [Screen visibleFrame];
		if (NSContainsRect(VisibleFrame, Frame) == NO)
		{
			// May need to scale the window to fit if it is larger than the new display.
			if (Frame.size.width > VisibleFrame.size.width || Frame.size.height > VisibleFrame.size.height)
			{
				NSRect NewFrame;
				NewFrame.size.width = Frame.size.width > VisibleFrame.size.width ? VisibleFrame.size.width : Frame.size.width;
				NewFrame.size.height = Frame.size.height > VisibleFrame.size.height ? VisibleFrame.size.height : Frame.size.height;
				NewFrame.origin = VisibleFrame.origin;
				
				[self setFrame:NewFrame display:NO];
			}
			else
			{
				NSRect Intersection = NSIntersectionRect(VisibleFrame, Frame);
				NSPoint Origin = Frame.origin;
				
				// If there's at least something on screen, try shifting it entirely on screen.
				if (Intersection.size.width > 0 && Intersection.size.height > 0)
				{
					CGFloat X = Frame.size.width - Intersection.size.width;
					CGFloat Y = Frame.size.height - Intersection.size.height;
					
					if (Intersection.size.width+Intersection.origin.x >= VisibleFrame.size.width+VisibleFrame.origin.x)
					{
						Origin.x -= X;
					}
					else if (Origin.x < VisibleFrame.origin.x)
					{
						Origin.x += X;
					}
					
					if (Intersection.size.height+Intersection.origin.y >= VisibleFrame.size.height+VisibleFrame.origin.y)
					{
						Origin.y -= Y;
					}
					else if (Origin.y < VisibleFrame.origin.y)
					{
						Origin.y += Y;
					}
				}
				else
				{
					Origin = VisibleFrame.origin;
				}
				
				[self setFrameOrigin:Origin];
			}
		}
	}
	else
	{
		GameThreadCall(^{
			if (MacApplication)
			{
				TSharedPtr<FMacWindow> Window = MacApplication->FindWindowByNSWindow(self);
				if (Window.IsValid())
				{
					MacApplication->OnWindowDidResize(Window.ToSharedRef(), false);
				}
			}
		}, @[ NSDefaultRunLoopMode ], false);
	}

	GameThreadCall(^{
		if (MacApplication)
		{
			TSharedPtr<FMacWindow> Window = MacApplication->FindWindowByNSWindow(self);
			if (Window.IsValid())
			{
				MacApplication->OnWindowChangedScreen(Window.ToSharedRef());
			}
		}
	}, @[ NSDefaultRunLoopMode ], false);
}

- (void)windowWillStartLiveResize:(NSNotification*)Notification
{
	SCOPED_AUTORELEASE_POOL;
	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
}

- (void)windowDidEndLiveResize:(NSNotification*)Notification
{
	SCOPED_AUTORELEASE_POOL;
	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
}

- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
	SCOPED_AUTORELEASE_POOL;
	if (MacApplication && sender == self && !bIsBeingOrderedFront) // Skip informing Slate if we're simply changing the z order of windows
	{
		GameThreadCall(^{
			if (MacApplication) // Another check because game thread may destroy MacApplication before it gets here
			{
				TSharedPtr<FMacWindow> Window = MacApplication->FindWindowByNSWindow((FCocoaWindow*)sender);
				if (Window.IsValid())
				{
					MacApplication->OnWindowWillResize(Window.ToSharedRef());
				}
			}
		}, @[ NSDefaultRunLoopMode, UnrealResizeEventMode, UnrealShowEventMode, UnrealFullscreenEventMode ], true);
	}
	return frameSize;
}

- (void)windowDidResize:(NSNotification*)Notification
{
	SCOPED_AUTORELEASE_POOL;
	bZoomed = [self isZoomed];
	if (MacApplication)
	{
		bIsBeingResized = true;
		MacApplication->DeferEvent(Notification);
		bIsBeingResized = false;
	}
}

- (void)windowWillClose:(NSNotification*)Notification
{
	SCOPED_AUTORELEASE_POOL;

	[self setDelegate:nil];
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)Sender
{
	return NSDragOperationGeneric;
}

- (void)draggingExited:(id <NSDraggingInfo>)Sender
{
	SCOPED_AUTORELEASE_POOL;
	NSNotification* Notification = [NSNotification notificationWithName:NSDraggingExited object:Sender];
	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
}

- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)Sender
{
	SCOPED_AUTORELEASE_POOL;
	NSNotification* Notification = [NSNotification notificationWithName:NSDraggingUpdated object:Sender];
	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
	return NSDragOperationGeneric;
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)Sender
{
	SCOPED_AUTORELEASE_POOL;
	NSNotification* Notification = [NSNotification notificationWithName:NSPrepareForDragOperation object:Sender];
	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
	return YES;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)Sender
{
	SCOPED_AUTORELEASE_POOL;
	NSNotification* Notification = [NSNotification notificationWithName:NSPerformDragOperation object:Sender];
	if (MacApplication)
	{
		MacApplication->DeferEvent(Notification);
	}
	return YES;
}

#if WITH_ACCESSIBILITY

- (void)UpdateAccessibilityView:(AccessibleWidgetId) InAccessibilityWindowId
{
	checkf([NSThread isMainThread], TEXT("Updating accessibility view in FCocoaWindow from wrong Thread! Accessibility can only be done on Main Thread!"));
	NSView* OpenGLView = [self openGLView];
	// FCocoaAccessibilityView is the base class all custom NSViews must inherit from to support accessibility
	if([OpenGLView isKindOfClass:[FCocoaAccessibilityView class]])
	{
		FCocoaAccessibilityView* CurrentAccessibilityView = (FCocoaAccessibilityView*) OpenGLView;
		[CurrentAccessibilityView SetAccessibilityWindowAsAccessibilityChild: InAccessibilityWindowId];
	}
}

- (void)ClearAccessibilityView
{
	checkf([NSThread isMainThread], TEXT("Updating accessibility view in FCocoaWindow from wrong Thread! Accessibility can only be done on Main Thread!"));
	NSView* OpenGLView = [self openGLView];
	// FCocoaAccessibilityView is the base class all custom NSViews must inherit from to support accessibility
	if([OpenGLView isKindOfClass:[FCocoaAccessibilityView class]])
	{
		FCocoaAccessibilityView* CurrentAccessibilityView = (FCocoaAccessibilityView*) OpenGLView;
		[CurrentAccessibilityView RemoveAccessibilityWindow];
	}
}
#endif

- (BOOL)AllowMainWindow

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/GameFramework/GameUserSettings.h:402

Scope: file

Source code excerpt:

	int32 LastConfirmedFullscreenMode;

	/** Fullscreen mode to use when toggling between windowed and fullscreen. Same values as r.FullScreenMode. */
	UPROPERTY(config)
	int32 PreferredFullscreenMode;

	/** All settings will be wiped and set to default if the serialized version differs from UE_GAMEUSERSETTINGS_VERSION. */
	UPROPERTY(config)
	uint32 Version;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameEngine.cpp:307

Scope (from outer to inner):

file
function     void UGameEngine::ConditionallyOverrideSettings

Source code excerpt:

		{
			// -FullScreen
			static auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.FullScreenMode"));
			check(CVar);
			WindowMode = CVar->GetValueOnGameThread() == 0 ? EWindowMode::Fullscreen : EWindowMode::WindowedFullscreen;

			if (PLATFORM_WINDOWS && WindowMode == EWindowMode::Fullscreen)
			{
				// Handle fullscreen mode differently for D3D11/D3D12

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp:239

Scope (from outer to inner):

file
function     void UGameUserSettings::SetToDefaults

Source code excerpt:

	LastRecommendedScreenHeight = -1.0f;

	static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.FullScreenMode"));
	PreferredFullscreenMode = CVar->GetValueOnGameThread();

	ScalabilityQuality.SetDefaults();

	if (FApp::CanEverRender())
	{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp:356

Scope (from outer to inner):

file
function     void UGameUserSettings::SetPreferredFullscreenMode

Source code excerpt:

	PreferredFullscreenMode = Mode;

	auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.FullScreenMode"));
	if (CVar)
	{
		CVar->Set(Mode, ECVF_SetByGameSetting);
	}
}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp:549

Scope (from outer to inner):

file
function     void UGameUserSettings::LoadSettings

Source code excerpt:

	}

	// Update r.FullScreenMode CVar
	SetPreferredFullscreenMode(PreferredFullscreenMode);
}

void UGameUserSettings::RequestResolutionChange(int32 InResolutionX, int32 InResolutionY, EWindowMode::Type InWindowMode, bool bInDoOverrides /* = true */)
{
	if (FPlatformProperties::HasFixedResolution())

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp:3808

Scope (from outer to inner):

file
function     bool UGameViewportClient::HandleToggleFullscreenCommand

Source code excerpt:

	}

	static auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.FullScreenMode"));
	check(CVar);
	auto FullScreenMode = CVar->GetValueOnGameThread() == 0 ? EWindowMode::Fullscreen : EWindowMode::WindowedFullscreen;
	FullScreenMode = Viewport->IsFullscreen() ? EWindowMode::Windowed : FullScreenMode;

	if (PLATFORM_WINDOWS && FullScreenMode == EWindowMode::Fullscreen)
	{