11using Avalonia ;
22using Avalonia . Controls ;
3+ using Avalonia . Threading ;
34using CarinaStudio . Collections ;
45using CarinaStudio . MacOS . AppKit ;
56using 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