Skip to content

Commit 3a68467

Browse files
authored
Merge pull request #606 from emoacht/develop
Develop
2 parents 867ecb6 + e8e03e9 commit 3a68467

File tree

12 files changed

+237
-94
lines changed

12 files changed

+237
-94
lines changed

Source/Installer/Product.wxs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
3-
<Product Id="*" Name="Monitorian" Manufacturer="emoacht" Version="4.6.12"
3+
<Product Id="*" Name="Monitorian" Manufacturer="emoacht" Version="4.6.15"
44
Language="1033" Codepage="1252" UpgradeCode="{81A4D148-75D3-462E-938D-8C208FB48E3C}">
55
<Package Id="*" InstallerVersion="500" Compressed="yes"
66
InstallScope="perMachine" InstallPrivileges="elevated"

Source/Monitorian.Core/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
// You can specify all the values or you can default the Build and Revision Numbers
3434
// by using the '*' as shown below:
3535
// [assembly: AssemblyVersion("1.0.*")]
36-
[assembly: AssemblyVersion("4.6.12.0")]
37-
[assembly: AssemblyFileVersion("4.6.12.0")]
36+
[assembly: AssemblyVersion("4.6.15.0")]
37+
[assembly: AssemblyFileVersion("4.6.15.0")]
3838
[assembly: NeutralResourcesLanguage("en-US")]
3939

4040
// For unit test

Source/Monitorian/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
// You can specify all the values or you can default the Build and Revision Numbers
5252
// by using the '*' as shown below:
5353
// [assembly: AssemblyVersion("1.0.*")]
54-
[assembly: AssemblyVersion("4.6.12.0")]
55-
[assembly: AssemblyFileVersion("4.6.12.0")]
54+
[assembly: AssemblyVersion("4.6.15.0")]
55+
[assembly: AssemblyFileVersion("4.6.15.0")]
5656
[assembly: Guid("a4cc5362-9b08-465b-ad64-5cfabc72a4c7")]
5757
[assembly: NeutralResourcesLanguage("en-US")]

Source/ScreenFrame/CursorHelper.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ public static class CursorHelper
1919
#endregion
2020

2121
/// <summary>
22-
/// Gets the current point of cursor.
22+
/// Gets the current location of cursor.
2323
/// </summary>
24-
/// <returns>The point of cursor</returns>
25-
public static Point GetCursorPoint()
24+
/// <returns>Location of cursor</returns>
25+
public static Point GetCursorLocation()
2626
{
27-
return TryGetCursorPoint(out POINT point)
28-
? point
27+
return TryGetCursorLocation(out POINT location)
28+
? location
2929
: default(Point); // (0, 0)
3030
}
3131

32-
internal static bool TryGetCursorPoint(out POINT point)
32+
internal static bool TryGetCursorLocation(out POINT location)
3333
{
34-
return GetCursorPos(out point);
34+
return GetCursorPos(out location);
3535
}
3636
}

Source/ScreenFrame/Helper/Throttle.cs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,21 @@ namespace ScreenFrame.Helper;
88
/// </summary>
99
internal class Throttle
1010
{
11-
private static readonly TimeSpan _dueTime = TimeSpan.FromSeconds(0.2);
12-
private readonly Action _action;
11+
protected readonly TimeSpan _dueTime;
12+
protected readonly Action _action;
1313

14-
public Throttle(Action action) => this._action = action;
14+
public Throttle(TimeSpan dueTime, Action action)
15+
{
16+
if (dueTime <= TimeSpan.Zero)
17+
throw new ArgumentOutOfRangeException(nameof(dueTime), dueTime, "The time must be positive.");
18+
19+
this._dueTime = dueTime;
20+
this._action = action;
21+
}
1522

16-
private Task _lastWaitTask;
23+
protected Task _lastWaitTask;
1724

18-
public async Task PushAsync()
25+
public virtual async Task PushAsync()
1926
{
2027
var currentWaitTask = Task.Delay(_dueTime);
2128
_lastWaitTask = currentWaitTask;
@@ -29,14 +36,21 @@ public async Task PushAsync()
2936

3037
internal class Throttle<T>
3138
{
32-
private static readonly TimeSpan _dueTime = TimeSpan.FromSeconds(0.2);
33-
private readonly Action<T> _action;
39+
protected readonly TimeSpan _dueTime;
40+
protected readonly Action<T> _action;
41+
42+
public Throttle(TimeSpan dueTime, Action<T> action)
43+
{
44+
if (dueTime <= TimeSpan.Zero)
45+
throw new ArgumentOutOfRangeException(nameof(dueTime), dueTime, "The time must be positive.");
3446

35-
public Throttle(Action<T> action) => this._action = action;
47+
this._dueTime = dueTime;
48+
this._action = action;
49+
}
3650

37-
private Task _lastWaitTask;
51+
protected Task _lastWaitTask;
3852

39-
public async Task PushAsync(T value)
53+
public virtual async Task PushAsync(T value)
4054
{
4155
var currentWaitTask = Task.Delay(_dueTime);
4256
_lastWaitTask = currentWaitTask;
@@ -46,4 +60,24 @@ public async Task PushAsync(T value)
4660
_action?.Invoke(value);
4761
}
4862
}
63+
}
64+
65+
/// <summary>
66+
/// Rx Sample like operator
67+
/// </summary>
68+
internal class Sample : Throttle
69+
{
70+
public Sample(TimeSpan dueTime, Action action) : base(dueTime, action)
71+
{ }
72+
73+
public override async Task PushAsync()
74+
{
75+
if (_lastWaitTask is not null)
76+
return;
77+
78+
_lastWaitTask = Task.Delay(_dueTime);
79+
await _lastWaitTask;
80+
_action?.Invoke();
81+
_lastWaitTask = null;
82+
}
4983
}

Source/ScreenFrame/Movers/FloatWindowMover.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ protected override bool TryGetAdjacentLocation(double windowWidth, double window
5151
/// <returns>True if successfully gets</returns>
5252
protected bool TryGetAdjacentLocationToPivot(double windowWidth, double windowHeight, out Rect location)
5353
{
54-
if (!WindowHelper.TryGetTaskbar(out _, out TaskbarAlignment taskbarAlignment, out _))
54+
if (!WindowHelper.TryGetTaskbar(out _, out TaskbarAlignment taskbarAlignment))
5555
{
5656
location = default;
5757
return false;

Source/ScreenFrame/Movers/StickWindowMover.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,6 @@ protected bool TryGetAdjacentLocationToTaskbar(double windowWidth, double window
9090

9191
if (isShown)
9292
{
93-
if (OsVersion.Is11Build22621OrGreater &&
94-
(WindowHelper.TryGetStartButtonRect(out Rect buttonRect) ||
95-
WindowHelper.TryGetSystemPrimaryTaskbar(out buttonRect, out _)))
96-
{
97-
taskbarRect = new Rect(taskbarRect.Left, buttonRect.Top, taskbarRect.Width, buttonRect.Height);
98-
}
99-
10093
if (NotifyIconHelper.TryGetNotifyIconRect(_notifyIcon, out iconRect))
10194
{
10295
if (taskbarRect.Contains(

Source/ScreenFrame/NotifyIconContainer.cs

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using System.Windows;
44
using System.Windows.Forms;
55

6+
using ScreenFrame.Helper;
7+
68
namespace ScreenFrame;
79

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

248250
if (e.Button == MouseButtons.Right)
249251
{
250-
if (NotifyIconHelper.TryGetNotifyIconClickedPoint(NotifyIcon, out Point point))
251-
MouseRightButtonClick?.Invoke(this, point);
252+
if (NotifyIconHelper.TryGetNotifyIconCursorLocation(NotifyIcon, out Point location, isSubstitutable: true))
253+
MouseRightButtonClick?.Invoke(this, location);
252254
}
253255
else
254256
{
@@ -267,6 +269,103 @@ private void OnMouseDoubleClick(object sender, MouseEventArgs e)
267269

268270
#endregion
269271

272+
#region Hover
273+
274+
private readonly object _lock = new();
275+
276+
/// <summary>
277+
/// Occurs when mouse pointer entered the rectangle of NotifyIcon.
278+
/// </summary>
279+
public event EventHandler MouseHover
280+
{
281+
add
282+
{
283+
lock (_lock)
284+
{
285+
RegisterMouseMove();
286+
_mouseHover += value;
287+
}
288+
}
289+
remove
290+
{
291+
lock (_lock)
292+
{
293+
_mouseHover -= value;
294+
UnregisterMouseMove();
295+
}
296+
}
297+
}
298+
private event EventHandler _mouseHover;
299+
300+
/// <summary>
301+
/// Occurs when mouse pointer left the rectangle of NotifyIcon.
302+
/// </summary>
303+
public event EventHandler MouseUnhover
304+
{
305+
add
306+
{
307+
lock (_lock)
308+
{
309+
RegisterMouseMove();
310+
_mouseUnhover += value;
311+
}
312+
}
313+
remove
314+
{
315+
lock (_lock)
316+
{
317+
_mouseUnhover -= value;
318+
UnregisterMouseMove();
319+
}
320+
}
321+
}
322+
private event EventHandler _mouseUnhover;
323+
324+
private void RegisterMouseMove()
325+
{
326+
if ((_mouseHover is null) &&
327+
(_mouseUnhover is null))
328+
{
329+
NotifyIcon.MouseMove += OnMouseMove;
330+
}
331+
}
332+
333+
private void UnregisterMouseMove()
334+
{
335+
if ((_mouseHover is null) &&
336+
(_mouseUnhover is null))
337+
{
338+
NotifyIcon.MouseMove -= OnMouseMove;
339+
}
340+
}
341+
342+
private Sample _reactMouseHover;
343+
private bool _isHover;
344+
345+
private async void OnMouseMove(object sender, MouseEventArgs e)
346+
{
347+
_reactMouseHover ??= new Sample(
348+
TimeSpan.FromSeconds(0.1),
349+
() =>
350+
{
351+
if (_isHover != NotifyIconHelper.TryGetNotifyIconCursorLocation(NotifyIcon, out _, isSubstitutable: false))
352+
{
353+
_isHover = !_isHover;
354+
if (_isHover)
355+
{
356+
_mouseHover?.Invoke(this, EventArgs.Empty);
357+
}
358+
else
359+
{
360+
_mouseUnhover?.Invoke(this, EventArgs.Empty);
361+
}
362+
}
363+
});
364+
await _reactMouseHover.PushAsync();
365+
}
366+
367+
#endregion
368+
270369
#region IDisposable
271370

272371
private bool _isDisposed = false;

Source/ScreenFrame/NotifyIconHelper.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,30 @@ public static bool SetNotifyIconWindowForeground(NotifyIcon notifyIcon)
4242
}
4343

4444
/// <summary>
45-
/// Attempts to get the point where a specified NotifyIcon is clicked.
45+
/// Attempts to get the location of cursor when cursor is over a specified NotifyIcon.
4646
/// </summary>
4747
/// <param name="notifyIcon">NotifyIcon</param>
48-
/// <param name="point">Clicked point</param>
48+
/// <param name="location">Location of cursor</param>
49+
/// <param name="isSubstitutable">Whether to substitute the NotifyIcon for cursor when cursor is not over the NotifyIcon</param>
4950
/// <returns>True if successfully gets</returns>
5051
/// <remarks>MouseEventArgs.Location property of MouseClick event does not contain data.</remarks>
51-
public static bool TryGetNotifyIconClickedPoint(NotifyIcon notifyIcon, out Point point)
52+
public static bool TryGetNotifyIconCursorLocation(NotifyIcon notifyIcon, out Point location, bool isSubstitutable)
5253
{
5354
if (TryGetNotifyIconRect(notifyIcon, out Rect iconRect))
5455
{
55-
if (CursorHelper.TryGetCursorPoint(out POINT source))
56+
if (CursorHelper.TryGetCursorLocation(out POINT source))
5657
{
57-
point = source;
58-
if (iconRect.Contains(point))
58+
location = source;
59+
if (iconRect.Contains(location))
5960
return true;
6061
}
61-
point = iconRect.Location; // Fallback
62-
return true;
62+
if (isSubstitutable)
63+
{
64+
location = iconRect.Location;
65+
return true;
66+
}
6367
}
64-
point = default;
68+
location = default;
6569
return false;
6670
}
6771

Source/ScreenFrame/Painter/WindowPainter.cs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -204,25 +204,29 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b
204204

205205
private async void OnThemeChanged()
206206
{
207-
_applyChangedTheme ??= new Throttle(() =>
208-
{
209-
if (ApplyChangedTheme())
207+
_applyChangedTheme ??= new Throttle(
208+
TimeSpan.FromSeconds(0.2),
209+
() =>
210210
{
211-
ThemeChanged?.Invoke(null, EventArgs.Empty);
212-
}
213-
});
211+
if (ApplyChangedTheme())
212+
{
213+
ThemeChanged?.Invoke(null, EventArgs.Empty);
214+
}
215+
});
214216
await _applyChangedTheme.PushAsync();
215217
}
216218

217219
private async void OnAccentColorChanged(Color color)
218220
{
219-
_applyChangedAccentColor ??= new Throttle<Color>(c =>
220-
{
221-
if (ApplyChangedAccentColor(c))
221+
_applyChangedAccentColor ??= new Throttle<Color>(
222+
TimeSpan.FromSeconds(0.2),
223+
c =>
222224
{
223-
AccentColorChanged?.Invoke(null, EventArgs.Empty);
224-
}
225-
});
225+
if (ApplyChangedAccentColor(c))
226+
{
227+
AccentColorChanged?.Invoke(null, EventArgs.Empty);
228+
}
229+
});
226230
await _applyChangedAccentColor.PushAsync(color);
227231
}
228232

0 commit comments

Comments
 (0)