- 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
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes fromall commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
155 changes: 105 additions & 50 deletionsApp/Views/TrayWindow.xaml.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -33,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; | ||
@@ -98,18 +96,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( | ||
@@ -225,7 +223,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 +231,6 @@ private void MoveResizeAndActivate() | ||
ForegroundWindow.MakeForeground(this); | ||
} | ||
private SizeInt32 CalculateWindowSize(double height) | ||
{ | ||
if (height <= 0) height = 100; // will be resolved next frame typically | ||
@@ -257,41 +242,44 @@ private SizeInt32 CalculateWindowSize(double height) | ||
return new SizeInt32(newWidth, newHeight); | ||
} | ||
private PointInt32 CalculateWindowPosition(SizeInt32panelSize) | ||
{ | ||
var area = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Primary); | ||
// whole monitor | ||
var bounds = area.OuterBounds; | ||
// monitor minus taskbar | ||
var workArea = area.WorkArea; | ||
// get taskbar details - position, gap (size), auto-hide | ||
var tb = GetTaskbarInfo(area); | ||
// safe edges where tray window can touch the screen | ||
var safeRight = workArea.X + workArea.Width; | ||
var safeBottom = workArea.Y + workArea.Height; | ||
// if the taskbar is auto-hidden at the bottom, stay clear of its reveal band | ||
if (tb.Position == TaskbarPosition.Bottom && tb.AutoHide) | ||
safeBottom -= tb.Gap; // shift everything up by its thickness | ||
// pick corner & position the panel | ||
int x, y; | ||
ibetitsmike marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
switch (tb.Position) | ||
{ | ||
case TaskbarPosition.Left: // for Left we will stick to the left-bottom corner | ||
x = bounds.X + tb.Gap; // just right of the bar | ||
y = safeBottom - panelSize.Height; | ||
break; | ||
case TaskbarPosition.Top: // for Top we will stick to the top-right corner | ||
x = safeRight - panelSize.Width; | ||
y = bounds.Y + tb.Gap; // just below the bar | ||
break; | ||
default: // Bottom or Right bar we will stick to the bottom-right corner | ||
x = safeRight - panelSize.Width; | ||
y = safeBottom - panelSize.Height; | ||
break; | ||
} | ||
return new PointInt32(x, y); | ||
} | ||
@@ -342,4 +330,71 @@ public struct POINT | ||
public int Y; | ||
} | ||
} | ||
ibetitsmike marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
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); | ||
} |
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.