I have a fullscreen xna game that is supposed to run on a secondary screen if available. It all works fine getting it into fullscreen mode on the secondary screen. However, when i focus a window on the primary screen, the fullscreen application on the secondary screen unfocusses. AlwaysOnTop is not an option here, as this is not a form, but a fullscreen application. How would i go around and tackle this problem?
Full screen is usually supposed to only work if it has focus I think. You could always make the application a border less window that is the size of the monitor. So it is still "full screen" without having to have focus. I wrote some code a little while ago to do this and it really isn't that hard to do let me see if i can find it..
WindowPoint = Window.Position;
WindowPoint.X = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Location.X;
WindowPoint.Y = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Location.Y;
Window.Position = WindowPoint;
Window.IsBorderless = true;
graphics.PreferredBackBufferWidth = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Width;
graphics.PreferredBackBufferHeight = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Height;
graphics.IsFullScreen = false;
graphics.ApplyChanges();
I am sure that there is a better way to do this. I'm still learning myself but this gets the job done. On my computer AllScreens[0] is the second monitor and [1] is the primary monitor. Let me know if this helps. Good luck :)
Related
I just stumbled on this little annoying behavior, while adding full screen support on a sample program.
Creating a full screen window works, but as soon as I move any window (from another application) on the output that contains my fullscreen window, it automatically switches back to windowed.
Is there any way to prevent this behavior (so full screen window do not go back to windowed)?
As a reference, this is a small standalone example (so problem can be replicated easily).
Also if that is useful, I'm running on Windows 8.1.
I already tried to change WindowAssociationFlags and SwapChainFlags, both with no success, same as using FlipSequential instead of Discard
SharpDX.DXGI.Factory2 factory = new SharpDX.DXGI.Factory2();
SharpDX.DXGI.Adapter adapter = factory.GetAdapter(0);
var renderForm1 = new RenderForm("Form 1");
factory.MakeWindowAssociation(renderForm1.Handle, SharpDX.DXGI.WindowAssociationFlags.IgnoreAll);
Device device = new Device(adapter, DeviceCreationFlags.BgraSupport);
SharpDX.DXGI.SwapChainDescription sd = new SharpDX.DXGI.SwapChainDescription()
{
BufferCount = 2,
ModeDescription = new SharpDX.DXGI.ModeDescription(0, 0, new SharpDX.DXGI.Rational(50, 1), SharpDX.DXGI.Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = renderForm1.Handle,
SampleDescription = new SharpDX.DXGI.SampleDescription(1,0),
SwapEffect = SharpDX.DXGI.SwapEffect.Discard,
Usage = SharpDX.DXGI.Usage.RenderTargetOutput,
Flags = SharpDX.DXGI.SwapChainFlags.None
};
var swapChain1 = new SharpDX.DXGI.SwapChain(factory, device, sd);
renderForm1.Left = 1922; //Just hardcoded here to move window to second screen
renderForm1.Width = 1920;
renderForm1.Height = 1080;
renderForm1.FormBorderStyle = FormBorderStyle.None;
swapChain1.SetFullscreenState(true, null);
swapChain1.ResizeBuffers(2, 1920, 1080, SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.DXGI.SwapChainFlags.AllowModeSwitch);
var resource = Texture2D.FromSwapChain<Texture2D>(swapChain1, 0);
var renderView = new RenderTargetView(device, resource);
RenderLoop.Run(renderForm1, () =>
{
device.ImmediateContext.ClearRenderTargetView(renderView, new SharpDX.Color4(1, 0, 0, 1));
swapChain1.Present(1, SharpDX.DXGI.PresentFlags.None);
});
Edit:
I also tried a c++ sample (just taken DirectX11 basic tutorial from Microsoft and added full screen switch), this leads to the same behavior, so this is not a SharpDX specific issue.
I looked at the message loop, and once this occurs, first fullscreen mode is changed back to windowed, and I receive a WM_DISPLAYCHANGE message).
This sounds like expected behavior. If you have a full screen 'exclusive' mode swapchain and the associated window loses focus, the system automatically switches the application out of full screen mode back to windowed mode by design.
With a single monitor, it mostly works as long as you have your applications' window sized to fill the display. Users can't use the mouse to change focus of your window, and it requires something like ALT+TAB to switch focus.
With multiple monitors, it's a real problem. If you click on another window on another display, your app loses focus and the full screen mode is again switched out. There are also limitations that prevent you from setting full screen 'exclusive' mode on more than one monitor.
Furthermore, on Windows Vista or later the notion of 'exclusive' mode is an illusion: the GPU is always shared anyhow. The 'focus' application gets priority whether it is a full screen or a windowed swap chain.
For a Windows desktop apps you have three choices for a full screen style experience:
Use the traditional full screen 'exclusive' mode with a window sized to fill the display, along with setting the display mode which may not be what the user has set for Windows generally. Here you have IsWindowed = false.
You set the window size to fill the full display (i.e. maximized). You can use windows styles to ensure that the window has no frame which results in a full screen style experience (WS_POPUP). Here you have IsWindowed = true, and you should be sure to set DXGI_MWA_NO_ALT_ENTER to avoid allowing DXGI to try to take you to use the 1 case.
You can do the same as 2 with IsWindowed = true and the borderless window sized to match the screen, but you change the display mode to something other than the system default. This is commonly referred to as 'fake full screen'. The display mode gets changed back whenever you exit the application.
1 has all has all the problems with multi-tasking and focus we just described. 2 and 3 allow system notifications and other pop-ups to show up over the game and not force a mode switch. 2 and 3 also work a lot better in multi-monitor setups where you can play your game on one display and use other apps on another display. For multi-tasking most people to prefer a classic window style with a frame border.
Windows Store UWP notions of full screen mode is basically like 2 above. You can't change the display mode with a UWP.
Debugging a full-screen setup is quite challenging. With multiple monitors, 2 and 3 can work with your debugger on the other screen. For true full-screen exclusive mode, really the only option is to use remote debugging from another PC.
Another issue with 1 and 3 is that you can set the display mode to something that won't sync with the display leaving the user with a system with no UI and no way to exit. Ideally with the right driver setup, the DXGI enumeration list does not contain unsupported modes, but it is something to be aware of. For this reason, your UI for selecting a display mode should have a timeout and you should make sure there's a reasonable way to abort the application with the keyboard if the display mode fails to sync at some point in the future. Using the existing display mode as we do in 2 above is always the safest option.
The main reason to use full screen exclusive mode (1) above is to try to get 'flip' rather than 'blit' of the backbuffer/frontbuffer. For most modern systems, this is a negligible performance difference. The other reason to go through the pain of using it is for SLI/Crossfire multi-GPU rendering going to a single display. There are a number of other optimizations required to really make that scenario work, and it's pretty niche. You should seek out the vendor optimization guides for the details.
Most modern games default to using fake full screen rather than full screen 'exclusive' mode. They offer the ability to use a true windowed mode as many users want to be able to multi-task while playing (like looking up hints online, use IM or external voice chat, etc.). AAA Windows desktop games that want to support tuned high-performance gaming for SLI/Crossfire will offer a full screen 'exclusive' mode, but this requires some work to get working fully and entails more work than just some DXGI code.
See DXGI Overview and DirectX Graphics Infrastructure (DXGI): Best Practices
After several attempts and trials, here are the different workarounds I used, none are ideal but all are somehow better than getting a mode change.
1/Force cursor in the middle of the full screen window, with a keyboard shortcut to get control again.
This is not ideal since we can't really do anything while our part is running, but at least prevents accidental "disaster click". It does not prevent keyboard interaction either.
2/Use a DX9 renderer with a shared texture.
DX9 Swapchain can have it's parent window set to desktop, so it does not lose focus when moving to something else.
Having a focused window on top show little borders visible while moving it, but that is a bit more acceptable than losing everything.
Not future proof but guess will stay actual for a while.
3/Stay on Windows 7 and Disable DWM Service:
Doesn't work in Windows 8 anymore, but in my use case since most media companies I work for are still on Windows 7, it stays a valid solution for at least 5 to 10 years.
4/Force the DX11 Window on foreground
Basically continuously call SetForegroundWindow to avoid another window to take focus.
5/Prevent mode switch at presentation level.
Since on my application I got access to when presentation occurs, I use the following routine (before to call Present)
-Get Foreground window handle (using GetForegroundWindow), If Foreground handle is our fullscreen window, just call Present as usual.
If Foreground handle is not our fullscreen window, perform the following. Please note that visibility check is not needed, since even an invisible overlapping window will also cause a full screen loss! (seriously, this is just so bad...)
-Verify if our foreground window overlaps with the monitor:
Call GetWindowRect to get the bounds, and perform intersection with the monitor location.
Alternatively, call Present on the swapchain with the DXGI_PRESENT_TEST flag. If a window is overlapping, the Present call will return DXGI_STATUS_OCCLUDED
If a window overlaps, either Hide it or move it in another monitor (anywhere so it does not overlap):
ShowWindow and SetWindowPos are aperfect fit for this task.
Repeat that Test present call in a loop until it doesn't return the occluded status (this is important, since windows might not have processed the messages immediately); Once occluded flag is gone, call Present as usual.
There is a way to prevent DXGI from automatically leaving fullscreen mode when your process loses focus, though I must warn, it is a bit hackish.
Basically DXGI calls GetForegroundWindow() and checks if the returned window is yours.
If not, it switches off the fullscreen mode.
So if you hook/redirect this function to your own replacement, that always returns your window (regardless of whether it has the focus or not) - that will get the job done.
Here is a simple code that does that. It is for 64-bit mode and assumes that you NEVER need to call the real function, so it simply overwrites its start with a jump instruction to your replacement:
HWND WINAPI get_our_window()
{
return our_window;
}
void disable_automatic_leaving_fullscreen_on_lost_focus()
{
// get the address of GetForegroundWindow
char *p = (char *)GetProcAddress(GetModuleHandleA("user32.dll"), "GetForegroundWindow");
// make the function code writable
DWORD old;
VirtualProtect(p, 12, PAGE_EXECUTE_WRITECOPY, &old);
// overwrite the function start:
// mov rax, <address_of_GetOurWindow>
p[0] = 0x48, p[1] = 0xB8, *(void **)(p + 2) = (void *)get_our_window;
// jmp rax
p[10] = 0xFF, p[11] = 0xE0;
}
This code is only for demonstration.
If you need to retain the ability to call the true function, then you have to hook it in a different, more complicated way, but this is a separate subject
I'm working on a small educational piece of work, I create a window and its supposed to cover the entire monitor. However "special" areas are not being covered as seen in the screnshot at bottom. My window is a solid red with no menu bar scroll bar etc, is there anyway to make this cover the top menu bar and the dock. In my screenshot I am testing on Ubuntu and Mint, this is consistent behavior on Gtk OS's I need to be ablve ot set my window so it covers all things is this possible?
I tried gdk_window_fullscreen but it's not doing anything, not even fullscreen, do you think its because I'm running this function from another thread? How would I know if this function needs to be run from the main thread?
Incomplete coverage on Ubuntu:
Incomplete coverage on Mint:
Code Tried
A frameless window is opened using Firefox code from main thread:
var aEditorDOMWindow = Services.ww.openWindow(null, core.addon.path.content + 'panel.xul', '_blank', 'chrome,width=1,height=1,screenX=0,screenY=0', null);
Now after load of it completes then the GdkWindow* of this window is obtained on the main thread and passed to another thread as a string
The thread now takes the string to GdkWindow* then that to GtkWindow*
var gdkWinPtr = ostypes.TYPE.GdkWindow.ptr(ctypes.UInt64(aHwndStr));
var gtkWinPtr = ostypes.HELPER.gdkWinPtrToGtkWinPtr(gdkWinPtr);
The thread then executes gtk_window_set_keep_above because if there was another app was focused it will focus this guy, and it will keep him on top of existing full screen windows
var rez_topIt = ostypes.API('gtk_window_set_keep_above')(gtkWinPtr, true);
The thread used to then run gtk_window_present but I removed it as I noticed it would crash the app, this was the code:
var rez_focus = ostypes.API('gtk_window_present')(gtkWinPtr);
EXPERIMENTAL STUFF I tried but it didnt work to make the window cover the special UI:
ostypes.API('gdk_window_set_type_hint')(gdkWinPtr, ostypes.CONST.WINDOW_TYPE_HINT_SPLASHSCREEN);
ostypes.API('gtk_window_set_position')(gtkWinPtr, ostypes.CONST.GTK_WIN_POS_NONE);
var geom = ostypes.TYPE.GdkGeometry();
geom.max_width = aOptions.fullWidth;
geom.max_height = aOptions.fullHeight;
var rez_geo = ostypes.API('gtk_window_set_geometry_hints')(gtkWinPtr, null, geom.address(), ostypes.CONST.GDK_HINT_MAX_SIZE);
Now the thread work is done and it goes to main thread. Now the main thread uses firefox javascript to move the window to top left most origin (which i calculated earlier with Gdk calls) and also sets the width and height of this window to that calculated of all the monitors (i did this earlier with other gdk calls)
aEditorDOMWindow.moveTo(collCanMonInfos[0].xTopLeft, collCanMonInfos[0].yTopLeft);
aEditorDOMWindow.resizeTo(collCanMonInfos[0].nWidth, collCanMonInfos[0].nHeight);
This results in the window SOMETIMES covering all monitors, other times just the one it opened on. And it never covers special UI like the taskbar/dock/menubars.
If you can please advise on how to acheive a window that fully covers everything that would be very appreciated, I'm trying to teach some people some stuff and I ran into a mess.
Here is a youtube video of the addon I am making: https://www.youtube.com/watch?v=aJM5NQK67N4
I discontinued using gdk_fullscreen because when it worked intermittently it would not allow the window to expand outside the one monitor.
Panels are usually implemented with struts, and window managers can decide never to allow windows to cover them; that's one of the reasons why the whole idea of "full screen window" was introduced: it gives the window manager a hint that the window that requested to be full screen should cover all other windows; have no decorations; and also cover all eventual "system" components, like panels.
I'm making a fairly complex sprite kit game. I recently added support for OS X. I get 60 fps always, regardless of how my game is scaled when the window is resized (even when resized to max screen space). However, the moment I make my App enter "Full Screen," the fps drops to 30-40 fps and stays that way? But if I take my mouse cursor and reveal the menu bar while full screen is enabled, the fps goes back up to 60 fps!
You can even test this bug by making a sprite kit game for mac in Xcode using the default template. Here are the screen shots I took of the default game template for mac.
I suggest trying it out for yourself, you don't even have to write any code if you use Apple's default sprite kit template for OS X.
Max Window (No FPS Problems: 59-60 FPS)
Full Screen Mode (FPS Drops to 30-40 FPS)
Full Screen Mode With Mouse At Top Revealing Menu Bar (Surprisingly, NO FPS Issues: 59-60 FPS)
Anyone have any idea what might be causing this problem. I don't want to release my App with full screen mode if it means users will lose performance. You would think full screen mode could better optimize drawing but apparently it's quite the opposite. I'm running this on Yosemite.
Ok, after weeks looking into this issue I have found some workarounds to this issue. Before I begin, let me start by explaining my setup. I'm using an NSViewController in a storyboard which holds an SKView. I've tested the workaround on MacBook Pro (Retina, 15-inch, Early 2013), I have no idea if the workarounds I present below will work on other Macs. I believe it should, when I get the chance I will test and see if the workarounds below work.
So before I begin, lets recap what the issue is. The issue is that making your App enter fullscreen by clicking the fullscreen button causes a massive drop in FPS. Below is how you enable the fullscreen button:
self.view.window!.collectionBehavior = .FullScreenPrimary
So then I searched around and found a different way of entering fullscreen using this code:
self.view.enterFullScreenMode(NSScreen.mainScreen()!, withOptions: nil)
But I still had a massive drop in FPS. Keep in mind, I had no fps issues when in maximized window mode or even full screen with the menu bar visible! (see pictures in question).
So then I tried a less high-level approach to going full screen. I found a guide by Apple here
Using some of the code from the guide, I managed to enter fullscreen by setting the window size to the size of the display, and positioning the window above all OS X UI. The code for this is as follows:
self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true
let size = NSScreen.mainScreen()!.frame.size
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height), display:true)
But, sadly, same problem... The FPS just dropped just like before.
So then I thought what if I mess with the size/position of the window. So I tried moving the window down so that just the menu bar was visible as shown below. AND THIS WORKED. I no longer had a drop in fps. But obviously it's not truly fullscreen because the menu bar is visible
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height-NSApplication.sharedApplication().mainMenu!.menuBarHeight), display:true)
In fact, as it turns out, just be adjusting the window size by 1 point fixes the drop in fps. Thus the bug must be related to an optimization (how ironic) apple does when your window size matches the screen size.
Don't believe me? Here is a quote from the link.
OS X v10.6 and later automatically optimize the performance of
screen-sized windows
So to fix the issue all we need to do is make our window size height 1 point larger which will prevent OS X from trying to optimize our window. This will cause your App to get slightly cut off on the top but 1 pixel shouldn't be noticeable at all. And in the worst case you could adjust your nodes position by 1 point to account for this.
For your convenience, listed below are the 2 workarounds. Both of these workarounds do not cause any drop in FPS. Your App should function just like it did in maximized window mode. The first workaround puts your App in fullscreen and displays the menu bar at the top. The second workaround puts your App in complete full screen with no menu bar.
Workaround 1: Fullscreen with Menu Bar
self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true
let size = NSScreen.mainScreen()!.frame.size
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height-NSApplication.sharedApplication().mainMenu!.menuBarHeight), display:true)
Workaround 2: Fullscreen with no Menu Bar
self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true
let size = NSScreen.mainScreen()!.frame.size
NSMenu.setMenuBarVisible(false)
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height+1), display:true)
If for some reason these workarounds don't work, try messing some more with the size/position of the window. Also you may need to change the window level depending on if you have other views such as dialogues that your App should not overlap. Also please remember to file bug reports with Apple.
Additional Info About NSBorderlessWindowMask
These workarounds use an NSBorderlessWindowMask. These type of windows do not accept keyboard input when the key window changes. So if your game uses keyboard input, you should override the following. See here
class CustomWindow: NSWindow {
override var canBecomeKeyWindow: Bool {
get {
return true
}
}
override var canBecomeMainWindow: Bool {
get {
return true
}
}
}
Update: Some bad news
Tested this workaround on Mac Book Air, and it did not work unless about 100 points were subtracted (which obviously is extremely noticeable). I have no idea why. Same goes for andyvn22's solution. I also have noticed that very rarely, perhaps once every 60 launches the workarounds provided simply don't work on the Mac Book Air at all. And the only way to fix is to relaunch the App. Maybe the Max Book Air is a special case. Maybe lack of a graphics card has to do with the issue. Hopefully Apple gets the issue sorted out. I'm now torn between supporting fullscreen and not supporting fullscreen. I really want users to be able to enter fullscreen mode, but at the same time I don't want to risk users loosing half their FPS.
Based on Epic Byte's very helpful work, I found an even easier way to disable Apple's full screen "optimization". You can still use OS X's built in full screen capability; all you have to do is implement the following method in your window's delegate:
func window(window: NSWindow, willUseFullScreenContentSize proposedSize: NSSize) -> NSSize {
return NSSize(width: proposedSize.width, height: proposedSize.height - 1)
}
Unfortunately adding one pixel doesn't seem to work this way, only subtracting one, so you lose a row of screen space. Totally worth it to me, though, to continue using the built-in full screen function, especially while just waiting for Apple to fix their optimization bug.
I believe this problem occurs on all apps using OpenGL to render. MPV (video player) with the following video config has the same issues: vo=opengl hwdec=no
Cpu usage - windowed: average 42%
Cpu usage - fullscreen (native): 62%
Cpu usage - fullscreen (non-native/in app): 60%
Cpu usage - fullscreen (native with menu bar): 45%
Cpu usage - offscreen (using native full screen): 95%
This also occurs on PPSSPP with OpenGL backend except with increased GPU instead of cpu usage:
Gpu usage - windowed: average 20%
Gpu usage - fullscreen (with menu bar): 20%
Gpu usage - fullscreen (native): 35%
Gpu usage - offscreen (using native full screen): 90%
This problem however does not seem to occur when developers implement their own "Special" fullscreen. In the case of Enter the Gungeon, where cpu usage and gpu usage shows no difference between windowed and FS. Although I haven't had time to check how they've implemented fullscreen yet.
Tested on MBP Late 2015 13' on OSX 10.11.6
The slightly increased usage during fullscreen is a bit annoying as you've said and can cause framedrops, but what's worrying me the most is the near 100% usage of both CPU and GPU in openGL applications when in background. (Note: it's 90% on ppsspp no matter what it's doing, even when paused).
I am trying to build a nice GUI with some glass effect in the client area.
So I implemented it as described here.
I was successful and have nice frame fully of glass, but only as long the window is not maximized. When I maximize the window it is only black :-(
With some googleing and experimenting I figured out, that when I invalidate the the window in response to a WM_WINDOWPOSCHANGING like this:
case WM_WINDOWPOSCHANGING: {
WINDOWPOS* pWindowPos = (WINDOWPOS*)lParam;
if (pWindowPos->flags & SWP_FRAMECHANGED) {
InvalidateRect(hWnd, NULL, TRUE);
}
}
I get the glass effect also when I maximize the window.
The odd thing now is that this is only working if I double click on the title bar or this the maximize button on the right top corner of the window. But if I move the window to the top of the screen to let it snap there to maximize the window (Aero Snap) the window turns just black.
Does anyone has a idea how this is done right?
(I am developing under Windows 7 64 bit.)
Edit:
I should also mention that I want to remove the standard title bar, I doing so by returning 0 in response to a WM_NCCALCSIZE message. Without this everything is working fine.
Edit:
A test on another system, which is basically the same was successful. The only notable difference is that there is another graphics card, a AMD Radeon HD 4300 instead of a AMD Radeon HD 5870. Could this be a issue with the driver of the graphics card?
Windows API has a method called GetForegroundWindow.
But it considers the Desktop as a foreground window when you click on it.
We all know that when it happens the previous foreground window isn't superposed by it.
How to get the real foreground window handle?
I think you're overengineering your solution. If your application window is not the foreground window when you receive an update, then flash the window. The point of flashing is to capture the user's attention, and you have no way to determine if you have their attention programmatically.
It seems like what you really want to know is: "Is the portion of my window that changes currently visible to the user?" That's quite a complex question to answer, and even if you answer it correctly, you have no way to know if the user will notice the change.
Both the "desktop" (Explorers desktop listview on top of the real desktop window) and the taskbar are real windows where the user might be "working" (Tab'ing around, using menus etc)
If you want to find the "real" foreground window that bad you have find it yourself, your best bet is going for the window at the top of the z-order, maybe something like:
... enumfunc(hwnd,...)
{
if (GetClassName(hwnd)!= "Shell_TrayWnd")
{
if (IsWindowEnabled(hwnd) && IsWindowVisible(hwnd) && GetWindow(hwnd,GW_OWNER)==NULL)
{
DoSomethingWithRealForegroundWindow(hwnd)
return FALSE
}
}
}
EnumWindows(enumfunc,0)
TaskSwitchXP is a open source alt-tab replacement, it probably has a better algorithm that you can use...