Tommi
Tommi

Reputation: 3247

WPF topmost option makes fullscreen app to escape

I used small window as a tooltip which shows "now playing" info in my application. Sure I set Topmost = "True" in window declaration and when new song starts to play I do tooltip.Show(). The problem is when I have fullscreen application in focus (game for example), .Show() call makes fullscreen window to became non-fullscreen, windowed, with border and top bar (as if I press Alt + Enter) and it looks like it loses focus also. So to restore fullscreen I need to click in window to focus it and press Alt-Enter manually. ShowActivated set to "False" already. So, I see three solutions:

1) Somehow make Topmost option to not cause to steal focus on .Show()

2) Use some workaround to make tooltip window "always on top" without Topmost option (I don't need to popup tooltip over fullscreen application since it can be (and probably will be) drawed via D3D or OpenGL)

3) Detect if system has fullscreen window in focus now and don't try to show tooltip.

I have no any clue how to fix behavior with any of this options, or maybe there is something more elegant?

Upvotes: 2

Views: 1433

Answers (2)

Tommi
Tommi

Reputation: 3247

So... in case anyone interested, here is my "research".

Solution 1) Failed. I found a few discussion about this behavior and some says it's a bug and the others it's a feature, but any of them assumes that it cannot be solved in managed code. I also tried attempt from Sheridan's answer with no luck.

Solution 2) Failed. I have some experience with P/Invoke but I generally fail if something goes wrong. In this particular case I tried to use

this.Handle = new WindowInteropHelper(this).Handle;
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);

as it suggested across web. This code does not show window. So I tried to show it with

ShowWindow(this.Handle, 4); // I also tried SHOW_NORMAL and few other flags

but window still was not visible

It becames visible if I do this.Visibility = /*visible*/ or this.Show(), and I really see that window is topmost, but it does not solve the issue and fullscreen escapes. If anyone knows how .Show() works internally and how I can show WPF window with P/Invoke, please let me know.

Solution 3) succeed. I found working code with a little googling here and slightly shortened it:

    internal class FullscreenCheck
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        [DllImport("user32.dll")]
        private static extern IntPtr GetDesktopWindow();
        [DllImport("user32.dll")]
        private static extern IntPtr GetShellWindow();
        [DllImport("user32.dll", SetLastError = true)]
        private static extern int GetWindowRect(IntPtr hwnd, out RECT rc);

        // I hope this handles never changes
        private static IntPtr hndlDesktop = GetDesktopWindow();
        private static IntPtr hndlShell   = GetShellWindow();

        public static bool IsFullscreen()
        {
            var hndlForeground = GetForegroundWindow();
            if (hndlForeground == null || hndlForeground == IntPtr.Zero || hndlForeground == hndlDesktop || hndlForeground == hndlShell)
            {
                return false;
            }

            RECT appBounds;
            GetWindowRect(hndlForeground, out appBounds);
            var screenBounds = System.Windows.Forms.Screen.FromHandle(hndlForeground).Bounds;

            return ((appBounds.Bottom - appBounds.Top) == screenBounds.Height && (appBounds.Right - appBounds.Left) == screenBounds.Width);
        }

So the last step is just not call .Show() if IsFullscreen() == true

Upvotes: 1

Sheridan
Sheridan

Reputation: 69987

I'm not totally sure about this, but how about trying this?:

tooltip.Owner = referenceToParentWindow;

If you launch this from MainWindow.xaml.cs, then you would use this:

tooltip.Owner = this;

If you launch this from outside the MainWindow.xaml.cs file, then you could (maybe) use this:

tooltip.Owner = Application.Current.MainWindow;

Upvotes: 0

Related Questions