bloxstrap/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs
pizzaboxer fd290f9ff7
Move activity watcher to separate process (#810)
this was done to:
- ensure robloxplayerbeta launches as an orphaned process
- help alleviate problems with multiple instances
- alleviate problems with the notifyicon causing blocking conflicts on the bootstrapper ui thread
- help reduce functional dependency on the bootstrapper, makes it less monolithic and more maintainable

ive always wanted to do this for a long while, but have always put it off because of how painful it would be

this may genuinely be the most painful refactoring i've ever had to do, but after 2 days, i managed to do it, and it works great!
2024-08-28 22:47:04 +01:00

134 lines
4.8 KiB
C#

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using Wpf.Ui.Appearance;
using Wpf.Ui.Mvvm.Contracts;
using Wpf.Ui.Mvvm.Services;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
using Bloxstrap.Integrations;
using Bloxstrap.Resources;
namespace Bloxstrap.UI.Elements.ContextMenu
{
/// <summary>
/// Interaction logic for NotifyIconMenu.xaml
/// </summary>
public partial class MenuContainer
{
// i wouldve gladly done this as mvvm but turns out that data binding just does not work with menuitems for some reason so idk this sucks
private readonly Watcher _watcher;
private ActivityWatcher? _activityWatcher => _watcher.ActivityWatcher;
private ServerInformation? _serverInformationWindow;
public MenuContainer(Watcher watcher)
{
InitializeComponent();
_watcher = watcher;
if (_activityWatcher is not null)
{
_activityWatcher.OnLogOpen += ActivityWatcher_OnLogOpen;
_activityWatcher.OnGameJoin += ActivityWatcher_OnGameJoin;
_activityWatcher.OnGameLeave += ActivityWatcher_OnGameLeave;
}
if (_watcher.RichPresence is not null)
RichPresenceMenuItem.Visibility = Visibility.Visible;
VersionTextBlock.Text = $"{App.ProjectName} v{App.Version}";
}
public void ShowServerInformationWindow()
{
if (_serverInformationWindow is null)
{
_serverInformationWindow = new ServerInformation(_watcher);
_serverInformationWindow.Closed += (_, _) => _serverInformationWindow = null;
}
if (!_serverInformationWindow.IsVisible)
_serverInformationWindow.Show();
_serverInformationWindow.Activate();
}
public void ActivityWatcher_OnLogOpen(object? sender, EventArgs e) =>
Dispatcher.Invoke(() => LogTracerMenuItem.Visibility = Visibility.Visible);
public void ActivityWatcher_OnGameJoin(object? sender, EventArgs e)
{
if (_activityWatcher is null)
return;
Dispatcher.Invoke(() => {
if (_activityWatcher.ActivityServerType == ServerType.Public)
InviteDeeplinkMenuItem.Visibility = Visibility.Visible;
ServerDetailsMenuItem.Visibility = Visibility.Visible;
});
}
public void ActivityWatcher_OnGameLeave(object? sender, EventArgs e)
{
Dispatcher.Invoke(() => {
InviteDeeplinkMenuItem.Visibility = Visibility.Collapsed;
ServerDetailsMenuItem.Visibility = Visibility.Collapsed;
_serverInformationWindow?.Close();
});
}
private void Window_Loaded(object? sender, RoutedEventArgs e)
{
// this is an awful hack lmao im so sorry to anyone who reads this
// this is done to register the context menu wrapper as a tool window so it doesnt appear in the alt+tab switcher
// https://stackoverflow.com/a/551847/11852173
HWND hWnd = (HWND)new WindowInteropHelper(this).Handle;
int exStyle = PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
exStyle |= 0x00000080; //NativeMethods.WS_EX_TOOLWINDOW;
PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, exStyle);
}
private void Window_Closed(object sender, EventArgs e) => App.Logger.WriteLine("MenuContainer::Window_Closed", "Context menu container closed");
private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) => _watcher.RichPresence?.SetVisibility(((MenuItem)sender).IsChecked);
private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetDataObject($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}");
private void ServerDetailsMenuItem_Click(object sender, RoutedEventArgs e) => ShowServerInformationWindow();
private void LogTracerMenuItem_Click(object sender, RoutedEventArgs e)
{
string? location = _activityWatcher?.LogLocation;
if (location is not null)
Utilities.ShellExecute(location);
}
private void CloseRobloxMenuItem_Click(object sender, RoutedEventArgs e)
{
MessageBoxResult result = Frontend.ShowMessageBox(
Strings.ContextMenu_CloseRobloxMessage,
MessageBoxImage.Warning,
MessageBoxButton.YesNo
);
if (result != MessageBoxResult.Yes)
return;
_watcher.KillRobloxProcess();
}
}
}