feature: supports using native window frame on Linux (#390)

This commit is contained in:
leo 2024-08-22 12:37:26 +08:00
parent eaf5eba0e7
commit d5e51d1f32
No known key found for this signature in database
26 changed files with 218 additions and 39 deletions

View file

@ -13,7 +13,7 @@
WindowStartupLocation="CenterScreen">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -13,7 +13,7 @@
WindowStartupLocation="CenterScreen">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -8,6 +8,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.AssumeUnchangedManager"
x:DataType="vm:AssumeUnchangedManager"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.AssumeUnchanged}"
Width="600" Height="400"
@ -15,7 +16,7 @@
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -7,18 +7,19 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Blame"
x:DataType="vm:Blame"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.Blame}"
MinWidth="1280" MinHeight="720">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="24"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<!-- Bottom border -->
<Border Grid.Column="0" Grid.ColumnSpan="4"
Background="{DynamicResource Brush.TitleBar}"

View file

@ -8,19 +8,20 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.BranchCompare"
x:DataType="vm:BranchCompare"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.BranchCompare}"
MinWidth="1280" MinHeight="720"
WindowStartupLocation="CenterOwner">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="64"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<!-- Bottom border -->
<Border Grid.Column="0" Grid.ColumnSpan="4"
Background="{DynamicResource Brush.TitleBar}"

View file

@ -8,14 +8,24 @@ namespace SourceGit.Views
{
public class ChromelessWindow : Window
{
public bool UseSystemWindowFrame
{
get => OperatingSystem.IsLinux() && ViewModels.Preference.Instance.UseSystemWindowFrame;
}
protected override Type StyleKeyOverride => typeof(Window);
public ChromelessWindow()
{
if (OperatingSystem.IsLinux())
Classes.Add("custom_window_frame");
{
if (!UseSystemWindowFrame)
Classes.Add("custom_window_frame");
}
else if (OperatingSystem.IsWindows())
{
Classes.Add("fix_maximized_padding");
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)

View file

@ -0,0 +1,65 @@
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.ConfirmRestart"
x:Name="ThisControl"
Title="Restart Required"
Icon="/App.ico"
CanResize="False"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
PointerPressed="BeginMoveWindow"/>
<Path Grid.Column="0"
Width="14" Height="14"
Margin="10,0,0,0"
Data="{StaticResource Icons.Info}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
Text="Restart Required"
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
</Grid>
<StackPanel Grid.Row="1" Margin="0,16" Orientation="Vertical">
<Border Margin="16,0">
<TextBlock Text="You need to restart this app to apply changes."/>
</Border>
<Button Classes="flat primary"
Width="80"
Margin="0,16,0,0"
Content="{DynamicResource Text.Sure}"
Click="Restart"
HorizontalAlignment="Center"
HotKey="Enter"/>
</StackPanel>
</Grid>
</v:ChromelessWindow>

View file

@ -0,0 +1,35 @@
using System;
using System.Diagnostics;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
public partial class ConfirmRestart : ChromelessWindow
{
public ConfirmRestart()
{
InitializeComponent();
}
private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
Console.Out.WriteLine("No passphrase entered.");
App.Quit(-1);
}
private void Restart(object _1, RoutedEventArgs _2)
{
var selfExecFile = Process.GetCurrentProcess().MainModule!.FileName;
Process.Start(selfExecFile);
App.Quit(-1);
}
}
}

View file

@ -9,18 +9,18 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.FileHistories"
x:DataType="vm:FileHistories"
x:Name="me"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.FileHistory}"
MinWidth="1280" MinHeight="720">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<!-- Bottom border -->
<Border Grid.Column="0" Grid.ColumnSpan="5"
Background="{DynamicResource Brush.TitleBar}"

View file

@ -7,6 +7,7 @@
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Hotkeys"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.Hotkeys}"
SizeToContent="WidthAndHeight"
@ -14,7 +15,7 @@
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -9,13 +9,14 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.InteractiveRebase"
x:DataType="vm:InteractiveRebase"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.InteractiveRebase}"
Width="1080" Height="720"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,Auto,*,Auto">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -7,13 +7,14 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.LFSLocks"
x:DataType="vm:LFSLocks"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.GitLFS.Locks.Title}"
Width="600" Height="400"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -8,13 +8,14 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Launcher"
x:DataType="vm:Launcher"
x:Name="ThisControl"
Icon="/App.ico"
Title="SourceGit"
MinWidth="1024" MinHeight="600"
WindowStartupLocation="CenterScreen">
<Grid x:Name="MainLayout">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="38"/>
<RowDefinition Height="{Binding #ThisControl.CaptionHeight}"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
@ -72,7 +73,7 @@
<v:LauncherTabBar Grid.Column="1" Height="30" VerticalAlignment="Bottom"/>
<!-- Caption Buttons (Windows/Linux)-->
<Border Grid.Column="2" Margin="32,0,0,0" IsVisible="{OnPlatform True, macOS=False}">
<Border Grid.Column="2" Margin="32,0,0,0" IsVisible="{Binding #ThisControl.IsRightCaptionButtonsVisible}">
<v:CaptionButtons Height="30" VerticalAlignment="Top"/>
</Border>
</Grid>

View file

@ -8,6 +8,25 @@ namespace SourceGit.Views
{
public partial class Launcher : ChromelessWindow
{
public static readonly StyledProperty<GridLength> CaptionHeightProperty =
AvaloniaProperty.Register<Launcher, GridLength>(nameof(CaptionHeight));
public GridLength CaptionHeight
{
get => GetValue(CaptionHeightProperty);
set => SetValue(CaptionHeightProperty, value);
}
public bool IsRightCaptionButtonsVisible
{
get
{
if (OperatingSystem.IsLinux())
return !ViewModels.Preference.Instance.UseSystemWindowFrame;
return OperatingSystem.IsWindows();
}
}
public Launcher()
{
var layout = ViewModels.Preference.Instance.Layout;
@ -17,6 +36,11 @@ namespace SourceGit.Views
Height = layout.LauncherHeight;
}
if (UseSystemWindowFrame)
CaptionHeight = new GridLength(30);
else
CaptionHeight = new GridLength(38);
InitializeComponent();
}
@ -38,13 +62,15 @@ namespace SourceGit.Views
{
base.OnPropertyChanged(change);
if (change.Property == WindowStateProperty && MainLayout != null)
if (change.Property == WindowStateProperty)
{
var state = (WindowState)change.NewValue!;
if (state == WindowState.Maximized)
MainLayout.RowDefinitions[0].Height = new GridLength(OperatingSystem.IsMacOS() ? 34 : 30);
if (OperatingSystem.IsLinux() && UseSystemWindowFrame)
CaptionHeight = new GridLength(30);
else if (state == WindowState.Maximized)
CaptionHeight = new GridLength(OperatingSystem.IsMacOS() ? 34 : 30);
else
MainLayout.RowDefinitions[0].Height = new GridLength(38);
CaptionHeight = new GridLength(38);
ViewModels.Preference.Instance.Layout.LauncherWindowState = state;
}

View file

@ -18,7 +18,7 @@
WindowStartupLocation="CenterScreen">
<Grid RowDefinitions="Auto,Auto" MinWidth="600">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
@ -57,7 +57,7 @@
<TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.General}"/>
</TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.General.Locale}"
HorizontalAlignment="Right"
@ -120,11 +120,6 @@
IsChecked="{Binding RestoreTabs, Mode=TwoWay}"/>
<CheckBox Grid.Row="5" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.General.UseFixedTabWidth}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth, Mode=TwoWay}"/>
<CheckBox Grid.Row="6" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.General.Check4UpdatesOnStartup}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=Check4UpdatesOnStartup, Mode=TwoWay}"/>
@ -135,7 +130,7 @@
<TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Appearance}"/>
</TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32,Auto" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.Appearance.Theme}"
HorizontalAlignment="Right"
@ -201,6 +196,18 @@
<CheckBox Grid.Row="5" Grid.Column="1"
Content="{DynamicResource Text.Preference.Appearance.OnlyUseMonoFontInEditor}"
IsChecked="{Binding OnlyUseMonoFontInEditor, Mode=TwoWay}"/>
<CheckBox Grid.Row="6" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.Appearance.UseFixedTabWidth}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth, Mode=TwoWay}"/>
<CheckBox Grid.Row="7" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.Appearance.UseNativeWindowFrame}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSystemWindowFrame, Mode=OneTime}"
IsVisible="{OnPlatform False, Linux=True}"
IsCheckedChanged="OnUseNativeWindowFrameChanged"/>
</Grid>
</TabItem>

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
@ -247,5 +248,19 @@ namespace SourceGit.Views
if (changed)
new Commands.Config(null).Set(key, value);
}
private void OnUseNativeWindowFrameChanged(object sender, RoutedEventArgs e)
{
if (sender is CheckBox box)
{
ViewModels.Preference.Instance.UseSystemWindowFrame = box.IsChecked == true;
ViewModels.Preference.Instance.Save();
var dialog = new ConfirmRestart();
App.OpenDialog(dialog);
}
e.Handled = true;
}
}
}

View file

@ -8,14 +8,15 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.RepositoryConfigure"
x:DataType="vm:RepositoryConfigure"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.Configure}"
Width="600" SizeToContent="Height"
CanResize="False"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,Auto,Auto">
<Grid RowDefinitions="Auto,Auto">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -9,6 +9,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.SelfUpdate"
x:DataType="vm:SelfUpdate"
x:Name="ThisControl"
Title="{DynamicResource Text.SelfUpdate.Title}"
Icon="/App.ico"
SizeToContent="WidthAndHeight"
@ -16,7 +17,7 @@
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -5,6 +5,7 @@
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.StandaloneCommitMessageEditor"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.CodeEditor}"
Width="800"
@ -13,7 +14,7 @@
WindowStartupLocation="CenterScreen">
<Grid RowDefinitions="Auto,*">
<!-- TitleBar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"

View file

@ -8,13 +8,14 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Statistics"
x:DataType="vm:Statistics"
x:Name="ThisControl"
Title="{DynamicResource Text.Statistics}"
Width="800" Height="450"
WindowStartupLocation="CenterOwner"
CanResize="False">
<Grid RowDefinitions="Auto,Auto,*">
<!-- Title bar -->
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Grid.Column="0" Grid.ColumnSpan="3"
Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"