-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1db45cb
commit c65357e
Showing
1 changed file
with
105 additions
and
132 deletions.
There are no files selected for viewing
This file contains 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 |
---|---|---|
@@ -1,160 +1,133 @@ | ||
using System.Runtime.InteropServices; | ||
using Avalonia; | ||
using Avalonia.Controls; | ||
using Avalonia.Threading; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using SupportCompanion.Interfaces; | ||
using SupportCompanion.Services; | ||
using SupportCompanion.ViewModels; | ||
|
||
namespace SupportCompanion.Views; | ||
|
||
public partial class TransparentWindow : Window, ITransparentWindow | ||
namespace SupportCompanion.Views | ||
{ | ||
private static readonly string DesktopPosition = App.Config.DesktopPosition; | ||
private readonly NotificationHandlerService _notificationHandlerService; | ||
|
||
public TransparentWindow() : this(new NotificationHandlerService()) | ||
{ | ||
} | ||
|
||
private TransparentWindow(NotificationHandlerService notificationHandler) | ||
{ | ||
InitializeComponent(); | ||
var viewModel = ((App)Application.Current).ServiceProvider.GetRequiredService<TransparentWindowViewModel>(); | ||
viewModel.TransparentWindow = this; | ||
DataContext = viewModel; | ||
PositionWindowInCorner(DesktopPosition); | ||
Opened += OnWindowOpened; | ||
ShowActivated = false; | ||
//_notificationHandlerService = notificationHandler; | ||
//_notificationHandlerService.Start(); | ||
//_notificationHandlerService.ScreenParametersChanged += OnScreenParametersChanged; | ||
} | ||
|
||
public void hide() | ||
{ | ||
base.Hide(); | ||
} | ||
|
||
public void show() | ||
{ | ||
base.Show(); | ||
} | ||
|
||
public void invalidateVisual() | ||
{ | ||
InvalidateVisual(); | ||
} | ||
|
||
private async void OnScreenParametersChanged(object sender, EventArgs e) | ||
public partial class TransparentWindow : Window, ITransparentWindow | ||
{ | ||
// Add a delay to ensure the window is repositioned after the screen has been resized | ||
await Task.Delay(2000); | ||
Dispatcher.UIThread.Post(() => | ||
private static readonly string DesktopPosition = App.Config.DesktopPosition; | ||
public TransparentWindow() | ||
{ | ||
InitializeComponent(); | ||
var viewModel = ((App)Application.Current).ServiceProvider.GetRequiredService<TransparentWindowViewModel>(); | ||
viewModel.TransparentWindow = this; | ||
DataContext = viewModel; | ||
PositionWindowInCorner(DesktopPosition); | ||
// Force a layout update | ||
InvalidateArrange(); | ||
InvalidateMeasure(); | ||
this.Opened += OnWindowOpened; | ||
this.ShowActivated = false; | ||
} | ||
|
||
public void hide() | ||
{ | ||
base.Hide(); | ||
} | ||
|
||
public void show() | ||
{ | ||
base.Show(); | ||
} | ||
|
||
public void invalidateVisual() | ||
{ | ||
InvalidateVisual(); | ||
}); | ||
} | ||
|
||
|
||
private void OnWindowOpened(object sender, EventArgs e) | ||
{ | ||
SetWindowProperties(); | ||
} | ||
|
||
private void SetWindowProperties() | ||
{ | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | ||
} | ||
|
||
private void OnWindowOpened(object sender, EventArgs e) | ||
{ | ||
var handle = GetNativeWindowHandle(); | ||
if (handle != IntPtr.Zero) | ||
SetWindowProperties(); | ||
} | ||
|
||
private void SetWindowProperties() | ||
{ | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | ||
{ | ||
// Set the window level to desktop, behind all other windows | ||
MacOSInterop.SetWindowLevel(handle, (int)NSWindowLevel.BelowDesktop); | ||
|
||
// Make the window ignore mouse events to prevent it from coming to the foreground | ||
MacOSInterop.SetIgnoresMouseEvents(handle, true); | ||
|
||
// Set collection behavior to stick the window to the desktop | ||
const int NSWindowCollectionBehaviorCanJoinAllSpaces = 1 << 0; | ||
const int NSWindowCollectionBehaviorStationary = 1 << 4; | ||
MacOSInterop.SetCollectionBehavior(handle, | ||
NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary); | ||
var handle = GetNativeWindowHandle(); | ||
if (handle != IntPtr.Zero) | ||
{ | ||
// Set the window level to desktop, behind all other windows | ||
MacOSInterop.SetWindowLevel(handle, (int)NSWindowLevel.BelowDesktop); | ||
|
||
// Make the window ignore mouse events to prevent it from coming to the foreground | ||
MacOSInterop.SetIgnoresMouseEvents(handle, true); | ||
|
||
// Set collection behavior to stick the window to the desktop | ||
const int NSWindowCollectionBehaviorCanJoinAllSpaces = 1 << 0; | ||
const int NSWindowCollectionBehaviorStationary = 1 << 4; | ||
MacOSInterop.SetCollectionBehavior(handle, | ||
NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private IntPtr GetNativeWindowHandle() | ||
{ | ||
var platformHandle = TryGetPlatformHandle(); | ||
return platformHandle?.Handle ?? IntPtr.Zero; | ||
} | ||
private IntPtr GetNativeWindowHandle() | ||
{ | ||
var platformHandle = this.TryGetPlatformHandle(); | ||
return platformHandle?.Handle ?? IntPtr.Zero; | ||
} | ||
|
||
private void PositionWindowInCorner(string corner) | ||
{ | ||
var screen = Screens.Primary.WorkingArea; | ||
PixelPoint newPosition; | ||
switch (corner) | ||
private enum NSWindowLevel | ||
{ | ||
case "BottomLeft": | ||
newPosition = new PixelPoint(screen.X, screen.Y + screen.Height - (int)Height); | ||
break; | ||
case "BottomRight": | ||
newPosition = new PixelPoint(screen.X + screen.Width - (int)Width, | ||
screen.Y + screen.Height - (int)Height); | ||
break; | ||
case "TopLeft": | ||
newPosition = new PixelPoint(screen.X, screen.Y); | ||
break; | ||
case "TopRight": | ||
newPosition = new PixelPoint(screen.X + screen.Width - (int)Width, screen.Y); | ||
break; | ||
default: | ||
throw new ArgumentException("Invalid corner specified"); | ||
Normal = 0, | ||
Desktop = -1, | ||
BelowDesktop = -2 | ||
} | ||
|
||
Position = newPosition; | ||
} | ||
private void PositionWindowInCorner(string corner) | ||
{ | ||
var screen = Screens.Primary.WorkingArea; | ||
|
||
private enum NSWindowLevel | ||
{ | ||
Normal = 0, | ||
Desktop = -1, | ||
BelowDesktop = -2 | ||
switch (corner) | ||
{ | ||
case "BottomLeft": | ||
Position = new PixelPoint(screen.X, screen.Y + screen.Height - (int)Height); | ||
break; | ||
case "BottomRight": | ||
Position = new PixelPoint(screen.X + screen.Width - (int)Width, | ||
screen.Y + screen.Height - (int)Height); | ||
break; | ||
case "TopLeft": | ||
Position = new PixelPoint(screen.X, screen.Y); | ||
break; | ||
case "TopRight": | ||
Position = new PixelPoint(screen.X + screen.Width - (int)Width, screen.Y); | ||
break; | ||
default: | ||
throw new ArgumentException("Invalid corner specified"); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public static class MacOSInterop | ||
{ | ||
[DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")] | ||
public static extern IntPtr objc_getClass(string className); | ||
|
||
[DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")] | ||
public static extern IntPtr sel_registerName(string selector); | ||
|
||
[DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")] | ||
public static extern void objc_msgSend(IntPtr receiver, IntPtr selector, IntPtr arg); | ||
|
||
public static void SetWindowLevel(IntPtr nsWindow, int level) | ||
|
||
public static class MacOSInterop | ||
{ | ||
var setLevelSelector = sel_registerName("setLevel:"); | ||
objc_msgSend(nsWindow, setLevelSelector, level); | ||
} | ||
[DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")] | ||
public static extern IntPtr objc_getClass(string className); | ||
|
||
public static void SetIgnoresMouseEvents(IntPtr nsWindow, bool ignores) | ||
{ | ||
var setIgnoresMouseEventsSelector = sel_registerName("setIgnoresMouseEvents:"); | ||
objc_msgSend(nsWindow, setIgnoresMouseEventsSelector, ignores ? 1 : 0); | ||
} | ||
[DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")] | ||
public static extern IntPtr sel_registerName(string selector); | ||
|
||
public static void SetCollectionBehavior(IntPtr nsWindow, int behavior) | ||
{ | ||
var setCollectionBehaviorSelector = sel_registerName("setCollectionBehavior:"); | ||
objc_msgSend(nsWindow, setCollectionBehaviorSelector, behavior); | ||
[DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")] | ||
public static extern void objc_msgSend(IntPtr receiver, IntPtr selector, IntPtr arg); | ||
|
||
public static void SetWindowLevel(IntPtr nsWindow, int level) | ||
{ | ||
IntPtr setLevelSelector = sel_registerName("setLevel:"); | ||
objc_msgSend(nsWindow, setLevelSelector, (IntPtr)level); | ||
} | ||
|
||
public static void SetIgnoresMouseEvents(IntPtr nsWindow, bool ignores) | ||
{ | ||
IntPtr setIgnoresMouseEventsSelector = sel_registerName("setIgnoresMouseEvents:"); | ||
objc_msgSend(nsWindow, setIgnoresMouseEventsSelector, (IntPtr)(ignores ? 1 : 0)); | ||
} | ||
|
||
public static void SetCollectionBehavior(IntPtr nsWindow, int behavior) | ||
{ | ||
IntPtr setCollectionBehaviorSelector = sel_registerName("setCollectionBehavior:"); | ||
objc_msgSend(nsWindow, setCollectionBehaviorSelector, (IntPtr)behavior); | ||
} | ||
} | ||
} |