Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/ManagedShell.AppBar/AppBarWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,9 @@ protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lPa
DpiHelper.DpiScale = DpiScale;
}

// suppress this if we are opening, because we're getting this message as a result of positioning
if (!IsOpening)
// if we are opening, we're getting this message as a result of positioning
// if we are an AppBar, that code will fix our position, so skip in that case to prevent infinite resizing.
if (!IsOpening || AppBarMode != AppBarMode.Normal)
{
ProcessScreenChange(ScreenSetupReason.DpiChange);
}
Expand Down
1 change: 1 addition & 0 deletions src/ManagedShell.AppBar/FullScreenApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public class FullScreenApp
public IntPtr hWnd;
public ScreenInfo screen;
public NativeMethods.Rect rect;
public string title;
}
}
92 changes: 76 additions & 16 deletions src/ManagedShell.AppBar/FullScreenHelper.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using ManagedShell.Common.Helpers;
using ManagedShell.Common.Logging;
using ManagedShell.WindowsTasks;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Threading;
using static ManagedShell.Interop.NativeMethods;
Expand All @@ -13,22 +13,46 @@ namespace ManagedShell.AppBar
{
public sealed class FullScreenHelper : IDisposable
{
private readonly DispatcherTimer fullscreenCheck;
private readonly DispatcherTimer _fullscreenCheck;
private readonly TasksService _tasksService;

public ObservableCollection<FullScreenApp> FullScreenApps = new ObservableCollection<FullScreenApp>();

public FullScreenHelper()
public FullScreenHelper(TasksService tasksService)
{
fullscreenCheck = new DispatcherTimer(DispatcherPriority.Background, System.Windows.Application.Current.Dispatcher)
_tasksService = tasksService;

if (_tasksService != null && EnvironmentHelper.IsWindows8OrBetter)
{
// On Windows 8 and newer, TasksService will tell us when windows enter and exit full screen
_tasksService.FullScreenEntered += TasksService_Event;
_tasksService.FullScreenLeft += TasksService_Event;
_tasksService.MonitorChanged += TasksService_Event;
_tasksService.DesktopActivated += TasksService_Event;
_tasksService.WindowActivated += TasksService_Event;
return;
}

_fullscreenCheck = new DispatcherTimer(DispatcherPriority.Background, System.Windows.Application.Current.Dispatcher)
{
Interval = new TimeSpan(0, 0, 0, 0, 100)
};

fullscreenCheck.Tick += FullscreenCheck_Tick;
fullscreenCheck.Start();
_fullscreenCheck.Tick += FullscreenCheck_Tick;
_fullscreenCheck.Start();
}

private void TasksService_Event(object sender, EventArgs e)
{
updateFullScreenWindows();
}

private void FullscreenCheck_Tick(object sender, EventArgs e)
{
updateFullScreenWindows();
}

private void updateFullScreenWindows()
{
IntPtr hWnd = GetForegroundWindow();

Expand All @@ -47,7 +71,7 @@ private void FullscreenCheck_Tick(object sender, EventArgs e)
continue;
}

if (appCurrentState != null && app.hWnd != hWnd &&
if (appCurrentState != null && app.hWnd != hWnd &&
app.screen.DeviceName == appCurrentState.screen.DeviceName &&
Screen.FromHandle(hWnd).DeviceName != appCurrentState.screen.DeviceName)
{
Expand All @@ -62,9 +86,9 @@ private void FullscreenCheck_Tick(object sender, EventArgs e)
// remove any changed windows we found
if (removeApps.Count > 0)
{
ShellLogger.Debug("Removing full screen app(s)");
foreach (FullScreenApp existingApp in removeApps)
{
ShellLogger.Debug($"FullScreenHelper: Removing full screen app {existingApp.hWnd} ({existingApp.title})");
FullScreenApps.Remove(existingApp);
}
}
Expand All @@ -75,7 +99,7 @@ private void FullscreenCheck_Tick(object sender, EventArgs e)
FullScreenApp appNew = getFullScreenApp(hWnd);
if (appNew != null)
{
ShellLogger.Debug("Adding full screen app");
ShellLogger.Debug($"FullScreenHelper: Adding full screen app {appNew.hWnd} ({appNew.title})");
FullScreenApps.Add(appNew);
}
}
Expand Down Expand Up @@ -118,10 +142,9 @@ private FullScreenApp getFullScreenApp(IntPtr hWnd)
return null;
}

// make sure this is not the shell desktop
StringBuilder cName = new StringBuilder(256);
GetClassName(hWnd, cName, cName.Capacity);
if (cName.ToString() == "Progman" || cName.ToString() == "WorkerW")
// Make sure this isn't explicitly marked as being non-rude
IntPtr isNonRudeHwnd = GetProp(hWnd, "NonRudeHWND");
if (isNonRudeHwnd != IntPtr.Zero)
{
return null;
}
Expand All @@ -137,8 +160,26 @@ private FullScreenApp getFullScreenApp(IntPtr hWnd)
}
}

ApplicationWindow win = new ApplicationWindow(null, hWnd);
if (!EnvironmentHelper.IsWindows8OrBetter)
{
// make sure this is not the shell desktop
// In Windows 8 and newer, the NonRudeHWND property is set and this is not needed
if (win.ClassName == "Progman" || win.ClassName == "WorkerW")
{
return null;
}
}

// make sure this is not a transparent window
int styles = win.ExtendedWindowStyles;
if ((styles & (int)ExtendedWindowStyles.WS_EX_LAYERED) != 0 && ((styles & (int)ExtendedWindowStyles.WS_EX_TRANSPARENT) != 0 || (styles & (int)ExtendedWindowStyles.WS_EX_NOACTIVATE) != 0))
{
return null;
}

// this is a full screen app on this screen
return new FullScreenApp { hWnd = hWnd, screen = screen, rect = rect };
return new FullScreenApp { hWnd = hWnd, screen = screen, rect = rect, title = win.Title };
}
}

Expand All @@ -148,7 +189,16 @@ private FullScreenApp getFullScreenApp(IntPtr hWnd)
private void ResetScreenCache()
{
// use reflection to empty screens cache
typeof(Screen).GetField("screens", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).SetValue(null, null);
const System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic;
var fi = typeof(Screen).GetField("screens", flags) ?? typeof(Screen).GetField("s_screens", flags);

if (fi == null)
{
ShellLogger.Warning("FullScreenHelper: Unable to reset screens cache");
return;
}

fi.SetValue(null, null);
}

public void NotifyScreensChanged()
Expand All @@ -158,7 +208,17 @@ public void NotifyScreensChanged()

public void Dispose()
{
fullscreenCheck.Stop();
_fullscreenCheck?.Stop();

if (_tasksService != null && EnvironmentHelper.IsWindows8OrBetter)
{
_tasksService.FullScreenEntered -= TasksService_Event;
_tasksService.FullScreenLeft -= TasksService_Event;
_tasksService.MonitorChanged -= TasksService_Event;
_tasksService.DesktopActivated -= TasksService_Event;
_tasksService.WindowActivated -= TasksService_Event;
return;
}
}
}
}
1 change: 1 addition & 0 deletions src/ManagedShell.AppBar/ManagedShell.AppBar.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ItemGroup>
<ProjectReference Include="..\ManagedShell.Common\ManagedShell.Common.csproj" />
<ProjectReference Include="..\ManagedShell.Interop\ManagedShell.Interop.csproj" />
<ProjectReference Include="..\ManagedShell.WindowsTasks\ManagedShell.WindowsTasks.csproj" />
<ProjectReference Include="..\ManagedShell.WindowsTray\ManagedShell.WindowsTray.csproj" />
</ItemGroup>

Expand Down
11 changes: 8 additions & 3 deletions src/ManagedShell.Common/SupportingClasses/NativeWindowEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ namespace ManagedShell.Common.SupportingClasses
{
public class NativeWindowEx : NativeWindow
{
public delegate void MessageReceivedEventHandler(Message m);
public delegate void MessageReceivedEventHandler(ref Message m, ref bool handled);

public event MessageReceivedEventHandler MessageReceived;

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
MessageReceived?.Invoke(m);
bool handled = false;
MessageReceived?.Invoke(ref m, ref handled);

if (!handled)
{
base.WndProc(ref m);
}
}

public override void CreateHandle(CreateParams cp)
Expand Down
4 changes: 2 additions & 2 deletions src/ManagedShell.Common/SupportingClasses/ShellWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public ShellWindow()
cp.Y = SystemInformation.VirtualScreen.Top;

CreateHandle(cp);
MessageReceived += WndProc;
MessageReceived += ShellWndProc;
NativeMethods.SetWindowLong(Handle, NativeMethods.GWL_EXSTYLE,
NativeMethods.GetWindowLong(Handle, NativeMethods.GWL_EXSTYLE) &
~(int)NativeMethods.ExtendedWindowStyles.WS_EX_NOACTIVATE);
Expand All @@ -47,7 +47,7 @@ public void Dispose()
NativeMethods.DestroyWindow(Handle);
}

private void WndProc(Message msg)
private void ShellWndProc(ref Message msg, ref bool handled)
{
// Window procedure for the native window
// Because other desktop windows are children, we need to pass them some received events.
Expand Down
22 changes: 20 additions & 2 deletions src/ManagedShell.Interop/NativeMethods.User32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ public struct COPYDATASTRUCT
public struct SHELLHOOKINFO
{
public IntPtr hwnd;
public Rect rc;
public ShortRect rc;
}

[StructLayout(LayoutKind.Sequential)]
Expand Down Expand Up @@ -1700,6 +1700,9 @@ public enum WindowShowStyle : uint
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);

[DllImport(User32_DllName)]
public static extern bool IsWindowEnabled(IntPtr hWnd);

[DllImport(User32_DllName)]
public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

Expand Down Expand Up @@ -1898,6 +1901,9 @@ public struct keyboardHookStruct
[DllImport(User32_DllName, SetLastError = true)]
public static extern IntPtr RemoveProp(IntPtr hWnd, string lpString);

[DllImport(User32_DllName, SetLastError = true)]
public static extern IntPtr GetProp(IntPtr hWnd, string lpString);

public enum TBPFLAG
{
TBPF_NOPROGRESS = 0,
Expand Down Expand Up @@ -2910,7 +2916,19 @@ public enum HSHELL : uint
/// </summary>
ENDTASK = 10,
FLASH = (REDRAW | HSHELL_HIGHBIT),
RUDEAPPACTIVATED = (WINDOWACTIVATED | HSHELL_HIGHBIT)
RUDEAPPACTIVATED = (WINDOWACTIVATED | HSHELL_HIGHBIT),
/// <summary>
/// A window has moved to another monitor. Windows 8 and newer only.
/// </summary>
MONITORCHANGED = 16,
/// <summary>
/// A window has become full-screen. Windows 8 and newer only.
/// </summary>
FULLSCREENENTER = 53,
/// <summary>
/// A window has left full-screen. Windows 8 and newer only.
/// </summary>
FULLSCREENEXIT = 54
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
Expand Down
24 changes: 24 additions & 0 deletions src/ManagedShell.Interop/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ public Rect(int left, int top, int right, int bottom)
public int Height => Bottom - Top;
}

/// <summary>
/// Used by HSHELL_GETMINRECT
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ShortRect
{
public ShortRect(short left, short top, short right, short bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}

public short Left;
public short Top;
public short Right;
public short Bottom;

public int Width => Right - Left;

public int Height => Bottom - Top;
}

public struct POINT
{
public POINT(long x, long y)
Expand Down
Loading