Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions FancyWM/Controls/TilingWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@
</StackPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem Command="{Binding IgnoreTitleCommand}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<ui:FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE82E;" FontSize="15" Margin="0, 0, 10, 0" />
<TextBlock Text="{x:Static res:Strings.Overlay_Window_AddRuleForTitle}" />
</StackPanel>
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</UserControl.ContextMenu>
<Grid>
Expand Down
6 changes: 4 additions & 2 deletions FancyWM/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,17 @@ await Dispatcher.InvokeAsync(() =>
.Select(_ => Unit.Default);

var exclusionListSettings = settings
.DistinctUntilChanged(x => (x.ProcessIgnoreList, x.ClassIgnoreList))
.DistinctUntilChanged(x => (x.ProcessIgnoreList, x.ClassIgnoreList, x.TitleIgnoreList))
.Do(async x => await Dispatcher.InvokeAsync(() =>
{
var processMatchers = x.ProcessIgnoreList.Select(x => new ByProcessNameMatcher(x));
var classMatchers = x.ClassIgnoreList.Select(x => new ByClassNameMatcher(x));
var titleMatchers = x.TitleIgnoreList.Select(x => new ByTitleMatcher(x));
m_tiling!.ExclusionMatchers = m_tiling.ExclusionMatchers
.Where(m => m is not ByProcessNameMatcher && m is not ByClassNameMatcher)
.Where(m => m is not ByProcessNameMatcher && m is not ByClassNameMatcher && m is not ByTitleMatcher)
.Concat(processMatchers)
.Concat(classMatchers)
.Concat(titleMatchers)
.ToArray();
}))
.Select(_ => Unit.Default);
Expand Down
2 changes: 2 additions & 0 deletions FancyWM/Models/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public Settings()
"RAIL_WINDOW",
];

public List<string> TitleIgnoreList { get; init; } = [];

public bool RemindToRateReview { get; init; } = true;

public bool ShowContextHints { get; init; } = true;
Expand Down
7 changes: 7 additions & 0 deletions FancyWM/Pages/Settings/RulesPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
<TextBlock HorizontalAlignment="Stretch" Padding="0,16,0,0" VerticalAlignment="Center" Foreground="{DynamicResource SystemControlPageTextBaseMediumBrush}" TextWrapping="Wrap" Text="{x:Static res:Strings.Rules_ClassIgnoreList_Description}" />
</StackPanel>
</Border>
<Border Style="{DynamicResource SettingsItemStyle}">
<StackPanel Orientation="Vertical">
<TextBlock VerticalAlignment="Center" Text="{x:Static res:Strings.Rules_TitleIgnoreList}" Margin="0, 0, 0, 16" />
<controls:StringsListBox ItemsSource="{Binding TitleIgnoreList, Mode=TwoWay}" />
<TextBlock HorizontalAlignment="Stretch" Padding="0,16,0,0" VerticalAlignment="Center" Foreground="{DynamicResource SystemControlPageTextBaseMediumBrush}" TextWrapping="Wrap" Text="{x:Static res:Strings.Rules_TitleIgnoreList_Description}" />
</StackPanel>
</Border>
</ui:SimpleStackPanel>
</Grid>
</UserControl>
31 changes: 29 additions & 2 deletions FancyWM/Resources/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions FancyWM/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,12 @@
<data name="Rules.ProcessIgnoreList.Description" xml:space="preserve">
<value>Floating mode will be automatically enabled for windows belonging to one of the processes. Enter one process name per line, excluding the ".exe" extension (e.g. "explorer"). The matching is not case-sensitive and you may use regular expressions.</value>
</data>
<data name="Rules.TitleIgnoreList" xml:space="preserve">
<value>Automatically float by window title</value>
</data>
<data name="Rules.TitleIgnoreList.Description" xml:space="preserve">
<value>Floating mode will be automatically enabled for windows with a matching title. The matching is not case-sensitive and you may use regular expressions.</value>
</data>
<data name="Settings" xml:space="preserve">
<value>Settings</value>
</data>
Expand Down Expand Up @@ -684,6 +690,9 @@
<data name="Overlay.Window.AddRuleForProcess" xml:space="preserve">
<value>Add floating rule for process</value>
</data>
<data name="Overlay.Window.AddRuleForTitle" xml:space="preserve">
<value>Add floating rule for window title</value>
</data>
<data name="Overlay.Window.MoreOptions" xml:space="preserve">
<value>More options</value>
</data>
Expand Down
8 changes: 8 additions & 0 deletions FancyWM/TilingOverlayRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class TilingOverlayRenderer : IDisposable
public event EventHandler<WindowNode>? FloatRequested;
public event EventHandler<WindowNode>? IgnoreProcessRequested;
public event EventHandler<WindowNode>? IgnoreClassRequested;
public event EventHandler<WindowNode>? IgnoreTitleRequested;
public event EventHandler<WindowNode>? BeginHorizontalWithRequested;
public event EventHandler<WindowNode>? BeginVerticalWithRequested;
public event EventHandler<WindowNode>? BeginStackWithRequested;
Expand Down Expand Up @@ -249,6 +250,7 @@ private void UpdateViewModels(IReadOnlyCollection<TilingNode> snapshot, IReadOnl
windowViewModel.StackActionPressed += WindowViewModel_StackActionPressed;
windowViewModel.IgnoreClassPressed += WindowViewModel_IgnoreClassPressed;
windowViewModel.IgnoreProcessPressed += WindowViewModel_IgnoreProcessPressed;
windowViewModel.IgnoreTitlePressed += WindowViewModel_IgnoreTitlePressed;
UpdateViewModel(windowViewModel, windowNode, focusedPath);
m_nodeViewModels.Add(node, windowViewModel);
return windowViewModel;
Expand Down Expand Up @@ -317,6 +319,11 @@ private void WindowViewModel_IgnoreClassPressed(object sender, RoutedEventArgs e
IgnoreClassRequested?.Invoke(this, ((WindowNode)((TilingWindowViewModel)sender!).Node!));
}

private void WindowViewModel_IgnoreTitlePressed(object sender, RoutedEventArgs e)
{
IgnoreTitleRequested?.Invoke(this, ((WindowNode)((TilingWindowViewModel)sender!).Node!));
}

private void OnSetPreviewWindows(IReadOnlySet<IWindow> oldValue, IReadOnlySet<IWindow> newValue)
{
foreach (var oldVm in m_nodeViewModels.Where(x => x.Key is WindowNode window && oldValue.Contains(window.WindowReference))
Expand Down Expand Up @@ -515,6 +522,7 @@ public void Dispose()
FloatRequested = null;
IgnoreProcessRequested = null;
IgnoreClassRequested = null;
IgnoreTitleRequested = null;
}
}
}
7 changes: 7 additions & 0 deletions FancyWM/TilingService.Private.cs
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,13 @@ private void OnWindowIgnoreClassRequested(object? sender, WindowNode e)
return x with { ClassIgnoreList = [.. x.ClassIgnoreList, ((WinMan.Windows.Win32Window)e.WindowReference).ClassName] };
});
}
private void OnWindowIgnoreTitleRequested(object? sender, WindowNode e)
{
App.Current.AppState.Settings.SaveAsync(x =>
{
return x with { TitleIgnoreList = [.. x.TitleIgnoreList, e.WindowReference.Title] };
});
}

private void OnTilingPanelMoving(object? sender, PanelNode panel)
{
Expand Down
1 change: 1 addition & 0 deletions FancyWM/TilingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ public TilingService(IWorkspace workspace, IDisplay display, IAnimationThread an
m_gui.StackRequested += OnWindowStackRequested;
m_gui.IgnoreProcessRequested += OnWindowIgnoreProcessRequested;
m_gui.IgnoreClassRequested += OnWindowIgnoreClassRequested;
m_gui.IgnoreTitleRequested += OnWindowIgnoreTitleRequested;

AutoRegisterWindows = autoRegisterWindows;

Expand Down
10 changes: 10 additions & 0 deletions FancyWM/Utilities/IWindowMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,14 @@ public bool Matches(IWindow window)
return (window is WinMan.Windows.Win32Window w) && MatchHelpers.IsMatch(w.ClassName, ClassName);
}
}

internal class ByTitleMatcher(string titlePattern) : IWindowMatcher
{
public string TitlePattern { get; } = titlePattern;

public bool Matches(IWindow window)
{
return MatchHelpers.IsMatch(window.Title, TitlePattern);
}
}
}
5 changes: 5 additions & 0 deletions FancyWM/ViewModels/SettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ public ObservableCollection<KeybindingViewModel>? Keybindings

public IList<string>? ClassIgnoreList { get => m_classIgnoreList; set => SetField(ref m_classIgnoreList, value); }

public IList<string>? TitleIgnoreList { get => m_titleIgnoreList; set => SetField(ref m_titleIgnoreList, value); }

public bool MultiMonitorSupport { get => m_multiMonitorSupport; set => SetField(ref m_multiMonitorSupport, value); }

public bool SoundOnFailure { get => m_soundOnFailure; set => SetField(ref m_soundOnFailure, value); }
Expand Down Expand Up @@ -218,6 +220,7 @@ public ObservableCollection<KeybindingViewModel>? Keybindings
private bool m_activateOnCapsLock;
private IList<string>? m_processIgnoreList;
private IList<string>? m_classIgnoreList;
private IList<string>? m_titleIgnoreList;
private bool m_multiMonitorSupport;
private bool m_showContextHints;
private bool m_soundOnFailure;
Expand Down Expand Up @@ -255,6 +258,7 @@ public SettingsViewModel(IObservableFileEntity<Settings> observable)
PanelFontSize = settings.PanelFontSize;
ProcessIgnoreList = settings.ProcessIgnoreList;
ClassIgnoreList = settings.ClassIgnoreList;
TitleIgnoreList = settings.TitleIgnoreList;
MultiMonitorSupport = settings.MultiMonitorSupport;
ShowContextHints = settings.ShowContextHints;
SoundOnFailure = settings.SoundOnFailure;
Expand Down Expand Up @@ -382,6 +386,7 @@ private void SaveChanges()
ShowContextHints = ShowContextHints,
ProcessIgnoreList = [.. ProcessIgnoreList!],
ClassIgnoreList = [.. ClassIgnoreList!],
TitleIgnoreList = [.. TitleIgnoreList!],
MultiMonitorSupport = MultiMonitorSupport,
SoundOnFailure = SoundOnFailure,
ShowFocus = ShowFocus,
Expand Down
4 changes: 4 additions & 0 deletions FancyWM/ViewModels/TilingWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ private enum RevealState
public event RoutedEventHandler? FloatActionPressed;
public event RoutedEventHandler? IgnoreProcessPressed;
public event RoutedEventHandler? IgnoreClassPressed;
public event RoutedEventHandler? IgnoreTitlePressed;

public ICommand BeginHorizontalSplitWithCommand { get; }
public ICommand BeginVerticalSplitWithCommand { get; }
Expand All @@ -67,6 +68,7 @@ private enum RevealState
public ICommand FloatCommand { get; }
public ICommand IgnoreProcessCommand { get; }
public ICommand IgnoreClassCommand { get; }
public ICommand IgnoreTitleCommand { get; }

public TilingWindowViewModel()
{
Expand All @@ -77,6 +79,7 @@ public TilingWindowViewModel()
FloatCommand = new DelegateCommand(_ => FloatActionPressed?.Invoke(this, new RoutedEventArgs()));
IgnoreProcessCommand = new DelegateCommand(_ => IgnoreProcessPressed?.Invoke(this, new RoutedEventArgs()));
IgnoreClassCommand = new DelegateCommand(_ => IgnoreClassPressed?.Invoke(this, new RoutedEventArgs()));
IgnoreTitleCommand = new DelegateCommand(_ => IgnoreTitlePressed?.Invoke(this, new RoutedEventArgs()));
}

public override void Dispose()
Expand All @@ -85,6 +88,7 @@ public override void Dispose()
FloatActionPressed = null;
IgnoreProcessPressed = null;
IgnoreClassPressed = null;
IgnoreTitlePressed = null;
Node = null;
}

Expand Down
Loading