Skip to content

Commit 1f88017

Browse files
committed
[Workaround] Update way of setting up window startup location on Linux.
1 parent 018fe8a commit 1f88017

File tree

4 files changed

+57
-30
lines changed

4 files changed

+57
-30
lines changed

Application.Avalonia.Tests/MainWindow.axaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
xmlns:sys="using:System"
77
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
88
x:Class="CarinaStudio.MainWindow"
9+
Height="600"
910
Icon="/AppIcon.ico"
10-
Title="Application.Avalonia.Tests">
11+
Title="Application.Avalonia.Tests"
12+
Width="800">
1113

1214
<Window.Resources>
1315
<sys:String x:Key="Title">Title in resources</sys:String>

Application.Avalonia.Tests/MainWindow.axaml.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,6 @@ public async Task Test()
282282
}
283283
*/
284284

285-
/*
286285
if (this.testDialog == null)
287286
{
288287
this.testDialog = new TestDialog().Also(it =>
@@ -293,7 +292,6 @@ public async Task Test()
293292
}
294293
else
295294
_ = new TestDialog().ShowDialog(this);
296-
*/
297295

298296
var transform = this.Find<Rectangle>("rect")?.RenderTransform as TranslateTransform;
299297
if (transform == null)

Application.Avalonia.Tests/TestDialog.axaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="300"
66
x:Class="CarinaStudio.TestDialog"
77
CanResize="False"
8-
SizeToContent="WidthAndHeight"
8+
SizeToContent="Height"
99
Title="TestDialog"
10-
WindowStartupLocation="CenterScreen">
10+
Width="300"
11+
WindowStartupLocation="CenterOwner">
1112

1213
<StackPanel>
1314
<Button Name="generateResultButton" Command="{Binding $parent[Window].GenerateResult}" Content="Generate result" HorizontalAlignment="Left" Margin="5"/>
14-
<Border Height="300" Width="400"/>
15+
<Border BorderBrush="Blue" BorderThickness="2" Height="200"/>
1516
</StackPanel>
1617

1718
</Window>

Avalonia/Controls/Window.cs

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Avalonia;
22
using Avalonia.Controls;
3+
using Avalonia.Threading;
34
using CarinaStudio.Collections;
45
using CarinaStudio.MacOS.AppKit;
56
using CarinaStudio.Threading;
@@ -43,6 +44,7 @@ public class Window : Avalonia.Controls.Window, ISynchronizable
4344
readonly ScheduledAction clearInitSizeObserversAction;
4445
PixelPoint? expectedInitPosition;
4546
Size? expectedInitSize;
47+
WindowStartupLocation desiredStartupLocation = WindowStartupLocation.Manual;
4648
bool hasDialogs;
4749
readonly IDisposable initHeightObserverToken;
4850
readonly IDisposable initWidthObserverToken;
@@ -219,6 +221,7 @@ protected override Size MeasureCore(Size availableSize)
219221
this.OnFirstMeasurementCompleted(size);
220222

221223
// [Workaround] move to actual center of owner/screen on Linux.
224+
this.desiredStartupLocation = this.WindowStartupLocation;
222225
if (Platform.IsLinux)
223226
{
224227
var titleBarHeightInPixels = WindowExtensions.GetTitleBarHeightInPixels();
@@ -228,29 +231,7 @@ protected override Size MeasureCore(Size availableSize)
228231
{
229232
case WindowStartupLocation.CenterOwner:
230233
{
231-
this.owner?.Let(owner =>
232-
{
233-
var screenScale = owner.Screens.ScreenFromVisual(owner)?.Scaling ?? 1.0;
234-
var titleBarHeight = titleBarHeightInPixels / screenScale;
235-
PixelPoint ownerPosition;
236-
Size ownerSize;
237-
if (owner is Window csWindow)
238-
{
239-
ownerPosition = csWindow.expectedInitPosition?.Let(it => new PixelPoint(it.X, (int)(it.Y + titleBarHeight * screenScale + 0.5))) ?? csWindow.Position;
240-
ownerSize = csWindow.expectedInitSize ?? new(csWindow.Width, csWindow.Height);
241-
}
242-
else
243-
{
244-
ownerPosition = owner.Position;
245-
ownerSize = new(owner.Width, owner.Height);
246-
}
247-
var offsetX = (int)((ownerSize.Width - width) / 2 * screenScale + 0.5);
248-
var offsetY = (int)((ownerSize.Height - height) / 2 * screenScale + 0.5);
249-
var position = new PixelPoint(ownerPosition.X + offsetX, ownerPosition.Y + offsetY);
250-
this.expectedInitPosition = position;
251-
this.expectedInitSize = new(width, height);
252-
this.WindowStartupLocation = WindowStartupLocation.Manual;
253-
});
234+
this.expectedInitSize = new(width, height);
254235
break;
255236
}
256237

@@ -340,7 +321,22 @@ void OnInitialPositionChanged(object? sender, PixelPointEventArgs e)
340321
{
341322
if (this.IsOpened)
342323
{
343-
this.Position = this.expectedInitPosition.Value;
324+
this.expectedInitPosition.Value.Let(it =>
325+
{
326+
Dispatcher.UIThread.Post(() =>
327+
{
328+
switch (this.desiredStartupLocation)
329+
{
330+
case WindowStartupLocation.CenterOwner:
331+
if (Math.Abs(e.Point.Y) < 1)
332+
this.Position = it;
333+
break;
334+
case WindowStartupLocation.CenterScreen:
335+
this.Position = it;
336+
break;
337+
}
338+
});
339+
});
344340
this.PositionChanged -= this.OnInitialPositionChanged;
345341
this.expectedInitPosition = null;
346342
}
@@ -378,6 +374,36 @@ void OnInitialWidthChanged(double width)
378374
/// <param name="e">Event data.</param>
379375
protected override void OnOpened(EventArgs e)
380376
{
377+
// [Workaround] move to actual center of owner/screen on Linux.
378+
if (Platform.IsLinux
379+
&& this.WindowStartupLocation == WindowStartupLocation.CenterOwner
380+
&& this.Owner is Avalonia.Controls.Window owner
381+
&& this.expectedInitSize.HasValue)
382+
{
383+
PixelPoint ownerPosition;
384+
Size ownerSize;
385+
var width = this.expectedInitSize.Value.Width;
386+
var height = this.expectedInitSize.Value.Height;
387+
var screenScale = this.Screens.ScreenFromVisual(this)?.Scaling ?? 1.0;
388+
var titleBarHeightInPixels = WindowExtensions.GetTitleBarHeightInPixels();
389+
var titleBarHeight = titleBarHeightInPixels / screenScale;
390+
if (owner is Window csWindow)
391+
{
392+
ownerPosition = csWindow.expectedInitPosition?.Let(it => new PixelPoint(it.X, (int)(it.Y + titleBarHeightInPixels))) ?? csWindow.Position;
393+
ownerSize = csWindow.expectedInitSize ?? new(csWindow.Width, csWindow.Height);
394+
}
395+
else
396+
{
397+
ownerPosition = owner.Position;
398+
ownerSize = new(owner.Width, owner.Height);
399+
}
400+
var offsetX = (int)((ownerSize.Width - width) / 2 * screenScale + 0.5);
401+
var offsetY = (int)((ownerSize.Height - height - titleBarHeight) / 2 * screenScale + 0.5 + titleBarHeightInPixels);
402+
var position = new PixelPoint(ownerPosition.X + offsetX, ownerPosition.Y + offsetY);
403+
this.expectedInitPosition = position;
404+
this.WindowStartupLocation = WindowStartupLocation.Manual;
405+
}
406+
381407
// notify owner
382408
this.owner = this.Owner as Window;
383409
this.owner?.OnChildWindowOpenedOrClosed(false);

0 commit comments

Comments
 (0)