- Notifications
You must be signed in to change notification settings - Fork5
feat: calculate taskbar position and display on top of it#125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -9,10 +9,9 @@ | ||||||||
using Microsoft.UI.Windowing; | ||||||||
using Microsoft.UI.Xaml; | ||||||||
using Microsoft.UI.Xaml.Controls; | ||||||||
using Microsoft.UI.Xaml.Media.Animation; | ||||||||
using System; | ||||||||
using System.Drawing.Printing; | ||||||||
using System.Runtime.InteropServices; | ||||||||
using Windows.Graphics; | ||||||||
using Windows.System; | ||||||||
@@ -34,8 +33,6 @@ public sealed partial class TrayWindow : Window | ||||||||
private int _lastWindowHeight; | ||||||||
private Storyboard? _currentSb; | ||||||||
private readonly IRpcController _rpcController; | ||||||||
private readonly ICredentialManager _credentialManager; | ||||||||
private readonly ISyncSessionController _syncSessionController; | ||||||||
@@ -60,7 +57,6 @@ public TrayWindow(IRpcController rpcController, ICredentialManager credentialMan | ||||||||
InitializeComponent(); | ||||||||
AppWindow.Hide(); | ||||||||
Activated += Window_Activated; | ||||||||
RootFrame.SizeChanged += RootFrame_SizeChanged; | ||||||||
@@ -97,18 +93,18 @@ public TrayWindow(IRpcController rpcController, ICredentialManager credentialMan | ||||||||
WindowNative.GetWindowHandle(this))); | ||||||||
SizeProxy.SizeChanged += (_, e) => | ||||||||
{ | ||||||||
if (_currentSb is null) return; // nothing running | ||||||||
var newHeight = (int)Math.Round( | ||||||||
e.NewSize.Height * DisplayScale.WindowScale(this)); | ||||||||
var delta = newHeight - _lastWindowHeight; | ||||||||
if (delta == 0) return; | ||||||||
var pos = _aw.Position; | ||||||||
var size = _aw.Size; | ||||||||
pos.Y -= delta; // grow upward | ||||||||
size.Height = newHeight; | ||||||||
_aw.MoveAndResize( | ||||||||
@@ -118,7 +114,6 @@ public TrayWindow(IRpcController rpcController, ICredentialManager credentialMan | ||||||||
}; | ||||||||
} | ||||||||
private void SetPageByState(RpcModel rpcModel, CredentialModel credentialModel, | ||||||||
SyncSessionControllerStateModel syncSessionModel) | ||||||||
{ | ||||||||
@@ -225,7 +220,6 @@ private void OnStoryboardCompleted(object? sender, object e) | ||||||||
private void MoveResizeAndActivate() | ||||||||
{ | ||||||||
var size = CalculateWindowSize(RootFrame.GetContentSize().Height); | ||||||||
var pos = CalculateWindowPosition(size); | ||||||||
var rect = new RectInt32(pos.X, pos.Y, size.Width, size.Height); | ||||||||
@@ -234,18 +228,6 @@ private void MoveResizeAndActivate() | ||||||||
NativeApi.SetForegroundWindow(WindowNative.GetWindowHandle(this)); | ||||||||
} | ||||||||
private SizeInt32 CalculateWindowSize(double height) | ||||||||
{ | ||||||||
if (height <= 0) height = 100; // will be resolved next frame typically | ||||||||
@@ -257,41 +239,38 @@ private SizeInt32 CalculateWindowSize(double height) | ||||||||
return new SizeInt32(newWidth, newHeight); | ||||||||
} | ||||||||
private PointInt32 CalculateWindowPosition(SizeInt32panelSize) | ||||||||
{ | ||||||||
var area = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Primary); | ||||||||
var bounds = area.OuterBounds; // entire monitor rect | ||||||||
var workArea = area.WorkArea; // monitor minus taskbar (and other app bars) | ||||||||
var tb = GetTaskbarInfo(area); | ||||||||
int x, y; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. The previous calculations had some hardcoded plus or minus | ||||||||
switch (tb.Position) | ||||||||
{ | ||||||||
case TaskbarPosition.Left: | ||||||||
x = bounds.X + tb.Gap; | ||||||||
y = workArea.Y + workArea.Height - panelSize.Height; | ||||||||
break; | ||||||||
case TaskbarPosition.Top: | ||||||||
x = workArea.X + workArea.Width - panelSize.Width; | ||||||||
y = bounds.Y + tb.Gap; | ||||||||
break; | ||||||||
case TaskbarPosition.Bottom when tb.AutoHide: | ||||||||
// Auto-hide bottom bar sits under the workArea – use workArea, not bounds. | ||||||||
x = workArea.X + workArea.Width - panelSize.Width; | ||||||||
y = workArea.Y + workArea.Height - panelSize.Height - tb.Gap; | ||||||||
break; | ||||||||
default: // right or bottom when not auto-hiding | ||||||||
x = workArea.X + workArea.Width - panelSize.Width; | ||||||||
y = bounds.Y + bounds.Height - panelSize.Height - tb.Gap; | ||||||||
break; | ||||||||
Comment on lines +263 to +272 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I don't get why we wouldn't just always use | ||||||||
} | ||||||||
return new PointInt32(x, y); | ||||||||
} | ||||||||
@@ -338,4 +317,70 @@ public struct POINT | ||||||||
public int Y; | ||||||||
} | ||||||||
} | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Suggested change
| ||||||||
internal enum TaskbarPosition { Left, Top, Right, Bottom } | ||||||||
internal readonly record struct TaskbarInfo(TaskbarPosition Position, int Gap, bool AutoHide); | ||||||||
// ----------------------------------------------------------------------------- | ||||||||
// Taskbar helpers – ABM_GETTASKBARPOS / ABM_GETSTATE via SHAppBarMessage | ||||||||
// ----------------------------------------------------------------------------- | ||||||||
private static TaskbarInfo GetTaskbarInfo(DisplayArea area) | ||||||||
{ | ||||||||
var data = new APPBARDATA | ||||||||
{ | ||||||||
cbSize = (uint)Marshal.SizeOf<APPBARDATA>() | ||||||||
}; | ||||||||
// Locate the taskbar. | ||||||||
if (SHAppBarMessage(ABM_GETTASKBARPOS, ref data) == 0) | ||||||||
return new TaskbarInfo(TaskbarPosition.Bottom, 0, false); // failsafe | ||||||||
var autoHide = (SHAppBarMessage(ABM_GETSTATE, ref data) & ABS_AUTOHIDE) != 0; | ||||||||
// Use uEdge instead of guessing from the RECT. | ||||||||
var pos = data.uEdge switch | ||||||||
{ | ||||||||
ABE_LEFT => TaskbarPosition.Left, | ||||||||
ABE_TOP => TaskbarPosition.Top, | ||||||||
ABE_RIGHT => TaskbarPosition.Right, | ||||||||
_ => TaskbarPosition.Bottom, // ABE_BOTTOM or anything unexpected | ||||||||
}; | ||||||||
// Thickness (gap) = shorter side of the rect. | ||||||||
var gap = (pos == TaskbarPosition.Left || pos == TaskbarPosition.Right) | ||||||||
? data.rc.right - data.rc.left // width | ||||||||
: data.rc.bottom - data.rc.top; // height | ||||||||
return new TaskbarInfo(pos, gap, autoHide); | ||||||||
} | ||||||||
// ------------- P/Invoke plumbing ------------- | ||||||||
private const uint ABM_GETTASKBARPOS = 0x0005; | ||||||||
private const uint ABM_GETSTATE = 0x0004; | ||||||||
private const int ABS_AUTOHIDE = 0x0001; | ||||||||
private const int ABE_LEFT = 0; // values returned in APPBARDATA.uEdge | ||||||||
private const int ABE_TOP = 1; | ||||||||
private const int ABE_RIGHT = 2; | ||||||||
private const int ABE_BOTTOM = 3; | ||||||||
[StructLayout(LayoutKind.Sequential)] | ||||||||
private struct APPBARDATA | ||||||||
{ | ||||||||
public uint cbSize; | ||||||||
public IntPtr hWnd; | ||||||||
public uint uCallbackMessage; | ||||||||
public uint uEdge; // contains ABE_* value | ||||||||
public RECT rc; | ||||||||
public int lParam; | ||||||||
} | ||||||||
[StructLayout(LayoutKind.Sequential)] | ||||||||
private struct RECT | ||||||||
{ | ||||||||
public int left, top, right, bottom; | ||||||||
} | ||||||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)] | ||||||||
private static extern uint SHAppBarMessage(uint dwMessage, ref APPBARDATA pData); | ||||||||
} |
Uh oh!
There was an error while loading.Please reload this page.