Skip to content

Commit

Permalink
Merge pull request #606 from emoacht/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
emoacht authored Jul 18, 2024
2 parents 867ecb6 + e8e03e9 commit 3a68467
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 94 deletions.
2 changes: 1 addition & 1 deletion Source/Installer/Product.wxs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="Monitorian" Manufacturer="emoacht" Version="4.6.12"
<Product Id="*" Name="Monitorian" Manufacturer="emoacht" Version="4.6.15"
Language="1033" Codepage="1252" UpgradeCode="{81A4D148-75D3-462E-938D-8C208FB48E3C}">
<Package Id="*" InstallerVersion="500" Compressed="yes"
InstallScope="perMachine" InstallPrivileges="elevated"
Expand Down
4 changes: 2 additions & 2 deletions Source/Monitorian.Core/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.6.12.0")]
[assembly: AssemblyFileVersion("4.6.12.0")]
[assembly: AssemblyVersion("4.6.15.0")]
[assembly: AssemblyFileVersion("4.6.15.0")]
[assembly: NeutralResourcesLanguage("en-US")]

// For unit test
Expand Down
4 changes: 2 additions & 2 deletions Source/Monitorian/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.6.12.0")]
[assembly: AssemblyFileVersion("4.6.12.0")]
[assembly: AssemblyVersion("4.6.15.0")]
[assembly: AssemblyFileVersion("4.6.15.0")]
[assembly: Guid("a4cc5362-9b08-465b-ad64-5cfabc72a4c7")]
[assembly: NeutralResourcesLanguage("en-US")]
14 changes: 7 additions & 7 deletions Source/ScreenFrame/CursorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ public static class CursorHelper
#endregion

/// <summary>
/// Gets the current point of cursor.
/// Gets the current location of cursor.
/// </summary>
/// <returns>The point of cursor</returns>
public static Point GetCursorPoint()
/// <returns>Location of cursor</returns>
public static Point GetCursorLocation()
{
return TryGetCursorPoint(out POINT point)
? point
return TryGetCursorLocation(out POINT location)
? location
: default(Point); // (0, 0)
}

internal static bool TryGetCursorPoint(out POINT point)
internal static bool TryGetCursorLocation(out POINT location)
{
return GetCursorPos(out point);
return GetCursorPos(out location);
}
}
54 changes: 44 additions & 10 deletions Source/ScreenFrame/Helper/Throttle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@ namespace ScreenFrame.Helper;
/// </summary>
internal class Throttle
{
private static readonly TimeSpan _dueTime = TimeSpan.FromSeconds(0.2);
private readonly Action _action;
protected readonly TimeSpan _dueTime;
protected readonly Action _action;

public Throttle(Action action) => this._action = action;
public Throttle(TimeSpan dueTime, Action action)
{
if (dueTime <= TimeSpan.Zero)
throw new ArgumentOutOfRangeException(nameof(dueTime), dueTime, "The time must be positive.");

this._dueTime = dueTime;
this._action = action;
}

private Task _lastWaitTask;
protected Task _lastWaitTask;

public async Task PushAsync()
public virtual async Task PushAsync()
{
var currentWaitTask = Task.Delay(_dueTime);
_lastWaitTask = currentWaitTask;
Expand All @@ -29,14 +36,21 @@ public async Task PushAsync()

internal class Throttle<T>
{
private static readonly TimeSpan _dueTime = TimeSpan.FromSeconds(0.2);
private readonly Action<T> _action;
protected readonly TimeSpan _dueTime;
protected readonly Action<T> _action;

public Throttle(TimeSpan dueTime, Action<T> action)
{
if (dueTime <= TimeSpan.Zero)
throw new ArgumentOutOfRangeException(nameof(dueTime), dueTime, "The time must be positive.");

public Throttle(Action<T> action) => this._action = action;
this._dueTime = dueTime;
this._action = action;
}

private Task _lastWaitTask;
protected Task _lastWaitTask;

public async Task PushAsync(T value)
public virtual async Task PushAsync(T value)
{
var currentWaitTask = Task.Delay(_dueTime);
_lastWaitTask = currentWaitTask;
Expand All @@ -46,4 +60,24 @@ public async Task PushAsync(T value)
_action?.Invoke(value);
}
}
}

/// <summary>
/// Rx Sample like operator
/// </summary>
internal class Sample : Throttle
{
public Sample(TimeSpan dueTime, Action action) : base(dueTime, action)
{ }

public override async Task PushAsync()
{
if (_lastWaitTask is not null)
return;

_lastWaitTask = Task.Delay(_dueTime);
await _lastWaitTask;
_action?.Invoke();
_lastWaitTask = null;
}
}
2 changes: 1 addition & 1 deletion Source/ScreenFrame/Movers/FloatWindowMover.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected override bool TryGetAdjacentLocation(double windowWidth, double window
/// <returns>True if successfully gets</returns>
protected bool TryGetAdjacentLocationToPivot(double windowWidth, double windowHeight, out Rect location)
{
if (!WindowHelper.TryGetTaskbar(out _, out TaskbarAlignment taskbarAlignment, out _))
if (!WindowHelper.TryGetTaskbar(out _, out TaskbarAlignment taskbarAlignment))
{
location = default;
return false;
Expand Down
7 changes: 0 additions & 7 deletions Source/ScreenFrame/Movers/StickWindowMover.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,6 @@ protected bool TryGetAdjacentLocationToTaskbar(double windowWidth, double window

if (isShown)
{
if (OsVersion.Is11Build22621OrGreater &&
(WindowHelper.TryGetStartButtonRect(out Rect buttonRect) ||
WindowHelper.TryGetSystemPrimaryTaskbar(out buttonRect, out _)))
{
taskbarRect = new Rect(taskbarRect.Left, buttonRect.Top, taskbarRect.Width, buttonRect.Height);
}

if (NotifyIconHelper.TryGetNotifyIconRect(_notifyIcon, out iconRect))
{
if (taskbarRect.Contains(
Expand Down
103 changes: 101 additions & 2 deletions Source/ScreenFrame/NotifyIconContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Windows;
using System.Windows.Forms;

using ScreenFrame.Helper;

namespace ScreenFrame;

/// <summary>
Expand Down Expand Up @@ -247,8 +249,8 @@ private void OnMouseClick(object sender, MouseEventArgs e)

if (e.Button == MouseButtons.Right)
{
if (NotifyIconHelper.TryGetNotifyIconClickedPoint(NotifyIcon, out Point point))
MouseRightButtonClick?.Invoke(this, point);
if (NotifyIconHelper.TryGetNotifyIconCursorLocation(NotifyIcon, out Point location, isSubstitutable: true))
MouseRightButtonClick?.Invoke(this, location);
}
else
{
Expand All @@ -267,6 +269,103 @@ private void OnMouseDoubleClick(object sender, MouseEventArgs e)

#endregion

#region Hover

private readonly object _lock = new();

/// <summary>
/// Occurs when mouse pointer entered the rectangle of NotifyIcon.
/// </summary>
public event EventHandler MouseHover
{
add
{
lock (_lock)
{
RegisterMouseMove();
_mouseHover += value;
}
}
remove
{
lock (_lock)
{
_mouseHover -= value;
UnregisterMouseMove();
}
}
}
private event EventHandler _mouseHover;

/// <summary>
/// Occurs when mouse pointer left the rectangle of NotifyIcon.
/// </summary>
public event EventHandler MouseUnhover
{
add
{
lock (_lock)
{
RegisterMouseMove();
_mouseUnhover += value;
}
}
remove
{
lock (_lock)
{
_mouseUnhover -= value;
UnregisterMouseMove();
}
}
}
private event EventHandler _mouseUnhover;

private void RegisterMouseMove()
{
if ((_mouseHover is null) &&
(_mouseUnhover is null))
{
NotifyIcon.MouseMove += OnMouseMove;
}
}

private void UnregisterMouseMove()
{
if ((_mouseHover is null) &&
(_mouseUnhover is null))
{
NotifyIcon.MouseMove -= OnMouseMove;
}
}

private Sample _reactMouseHover;
private bool _isHover;

private async void OnMouseMove(object sender, MouseEventArgs e)
{
_reactMouseHover ??= new Sample(
TimeSpan.FromSeconds(0.1),
() =>
{
if (_isHover != NotifyIconHelper.TryGetNotifyIconCursorLocation(NotifyIcon, out _, isSubstitutable: false))
{
_isHover = !_isHover;
if (_isHover)
{
_mouseHover?.Invoke(this, EventArgs.Empty);
}
else
{
_mouseUnhover?.Invoke(this, EventArgs.Empty);
}
}
});
await _reactMouseHover.PushAsync();
}

#endregion

#region IDisposable

private bool _isDisposed = false;
Expand Down
22 changes: 13 additions & 9 deletions Source/ScreenFrame/NotifyIconHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,30 @@ public static bool SetNotifyIconWindowForeground(NotifyIcon notifyIcon)
}

/// <summary>
/// Attempts to get the point where a specified NotifyIcon is clicked.
/// Attempts to get the location of cursor when cursor is over a specified NotifyIcon.
/// </summary>
/// <param name="notifyIcon">NotifyIcon</param>
/// <param name="point">Clicked point</param>
/// <param name="location">Location of cursor</param>
/// <param name="isSubstitutable">Whether to substitute the NotifyIcon for cursor when cursor is not over the NotifyIcon</param>
/// <returns>True if successfully gets</returns>
/// <remarks>MouseEventArgs.Location property of MouseClick event does not contain data.</remarks>
public static bool TryGetNotifyIconClickedPoint(NotifyIcon notifyIcon, out Point point)
public static bool TryGetNotifyIconCursorLocation(NotifyIcon notifyIcon, out Point location, bool isSubstitutable)
{
if (TryGetNotifyIconRect(notifyIcon, out Rect iconRect))
{
if (CursorHelper.TryGetCursorPoint(out POINT source))
if (CursorHelper.TryGetCursorLocation(out POINT source))
{
point = source;
if (iconRect.Contains(point))
location = source;
if (iconRect.Contains(location))
return true;
}
point = iconRect.Location; // Fallback
return true;
if (isSubstitutable)
{
location = iconRect.Location;
return true;
}
}
point = default;
location = default;
return false;
}

Expand Down
28 changes: 16 additions & 12 deletions Source/ScreenFrame/Painter/WindowPainter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,25 +204,29 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b

private async void OnThemeChanged()
{
_applyChangedTheme ??= new Throttle(() =>
{
if (ApplyChangedTheme())
_applyChangedTheme ??= new Throttle(
TimeSpan.FromSeconds(0.2),
() =>
{
ThemeChanged?.Invoke(null, EventArgs.Empty);
}
});
if (ApplyChangedTheme())
{
ThemeChanged?.Invoke(null, EventArgs.Empty);
}
});
await _applyChangedTheme.PushAsync();
}

private async void OnAccentColorChanged(Color color)
{
_applyChangedAccentColor ??= new Throttle<Color>(c =>
{
if (ApplyChangedAccentColor(c))
_applyChangedAccentColor ??= new Throttle<Color>(
TimeSpan.FromSeconds(0.2),
c =>
{
AccentColorChanged?.Invoke(null, EventArgs.Empty);
}
});
if (ApplyChangedAccentColor(c))
{
AccentColorChanged?.Invoke(null, EventArgs.Empty);
}
});
await _applyChangedAccentColor.PushAsync(color);
}

Expand Down
4 changes: 2 additions & 2 deletions Source/ScreenFrame/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.6.12.0")]
[assembly: AssemblyFileVersion("4.6.12.0")]
[assembly: AssemblyVersion("4.6.15.0")]
[assembly: AssemblyFileVersion("4.6.15.0")]
[assembly: NeutralResourcesLanguage("en-US")]
Loading

0 comments on commit 3a68467

Please sign in to comment.