Skip to content

Commit

Permalink
Merge pull request #992 from xoascf/clock-flyout-options
Browse files Browse the repository at this point in the history
Add clock click action settings
  • Loading branch information
dremin authored Jan 8, 2025
2 parents 29c977d + d91764b commit 7539928
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 49 deletions.
50 changes: 26 additions & 24 deletions RetroBar/Controls/Clock.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Windows.Threading;
using ManagedShell.Common.Helpers;
using ManagedShell.Common.Logging;
using ManagedShell.UWPInterop;
using Microsoft.Win32;
using RetroBar.Utilities;

Expand All @@ -27,7 +28,6 @@ public DateTime Now
}

private readonly DispatcherTimer clock = new DispatcherTimer(DispatcherPriority.Background);
private readonly DispatcherTimer singleClick = new DispatcherTimer(DispatcherPriority.Input);

private bool _isLoaded;

Expand All @@ -38,9 +38,6 @@ public Clock()

clock.Interval = TimeSpan.FromMilliseconds(200);
clock.Tick += Clock_Tick;

singleClick.Interval = TimeSpan.FromMilliseconds(System.Windows.Forms.SystemInformation.DoubleClickTime);
singleClick.Tick += SingleClick_Tick;
}

private void Initialize()
Expand All @@ -65,7 +62,7 @@ private void StartClock()
SetTime();

clock.Start();

Visibility = Visibility.Visible;
}

Expand Down Expand Up @@ -96,22 +93,6 @@ private void Clock_Tick(object sender, EventArgs args)
SetTime();
}

private void SingleClick_Tick(object sender, EventArgs args)
{
// Windows 10-11 single-click action
// A double-click will cancel the timer so that this doesn't run

singleClick.Stop();
if (EnvironmentHelper.IsWindows11OrBetter)
{
ShellHelper.ShowNotificationCenter();
}
else
{
ShellHelper.ShowActionCenter();
}
}

private void TimeChanged(object sender, EventArgs e)
{
TimeZoneInfo.ClearCachedData();
Expand Down Expand Up @@ -181,15 +162,36 @@ private void SetTime()

private void Clock_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (EnvironmentHelper.IsWindows10OrBetter)
switch (Settings.Instance.ClockClickAction)
{
singleClick.Start();
case ClockClickOption.OpenModernCalendar:
Point screenPosition = PointToScreen(new(0, 0));
ManagedShell.Interop.NativeMethods.Rect rect = new(
(int)screenPosition.X, (int)screenPosition.Y,
(int)(screenPosition.X + RenderSize.Width),
(int)(screenPosition.Y + RenderSize.Height)
);
ImmersiveShellHelper.ShowClockFlyout(rect);
break;
case ClockClickOption.OpenAeroCalendar:
IntPtr hWnd = (PresentationSource.FromVisual(this) as System.Windows.Interop.HwndSource).Handle;
ClockFlyoutLauncher.ShowAeroClockFlyout(hWnd);
break;
case ClockClickOption.OpenNotificationCenter:
if (EnvironmentHelper.IsWindows10RS4OrBetter)
{
ImmersiveShellHelper.ShowActionCenter();
}
else
{
ShellHelper.ShowActionCenter();
}
break;
}
}

private void Clock_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
singleClick.Stop();
ShellHelper.StartProcess("timedate.cpl");

e.Handled = true;
Expand Down
7 changes: 7 additions & 0 deletions RetroBar/Languages/English (United Kingdom).xaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
xmlns:s="clr-namespace:System;assembly=mscorlib">

<s:String x:Key="customize">_Customise...</s:String>
<x:Array x:Key="clock_click_action_values" Type="s:String">
<s:String>Do nothing</s:String>
<s:String>Open Aero calendar</s:String>
<s:String>Open Modern calendar</s:String>
<s:String>Open Notification Centre</s:String>
</x:Array>

<s:String x:Key="customize_notifications">Customise Notifications</s:String>
<s:String x:Key="customize_notifications_info">RetroBar displays icons for active and urgent notifications, and hides inactive ones. You can change this behaviour for items in the list below.</s:String>
<s:String x:Key="customize_notifications_instruction">Select an item, then choose its notification behaviour:</s:String>
Expand Down
7 changes: 7 additions & 0 deletions RetroBar/Languages/English.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@
<s:String>Open a new instance</s:String>
<s:String>Close the task</s:String>
</x:Array>
<s:String x:Key="clock_click_action">_Clock click action:</s:String>
<x:Array x:Key="clock_click_action_values" Type="s:String">
<s:String>Do nothing</s:String>
<s:String>Open Aero calendar</s:String>
<s:String>Open Modern calendar</s:String>
<s:String>Open Notification Center</s:String>
</x:Array>
<s:String x:Key="version">Version {0}</s:String>
<s:String x:Key="visit_on_github">Visit RetroBar on GitHub</s:String>
<s:String x:Key="taskbar_scale">Taskbar scale</s:String>
Expand Down
7 changes: 7 additions & 0 deletions RetroBar/Languages/español.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@
<s:String>Abrir una nueva instancia</s:String>
<s:String>Cerrar la tarea</s:String>
</x:Array>
<s:String x:Key="clock_click_action">_Acción al hacer clic en el reloj:</s:String>
<x:Array x:Key="clock_click_action_values" Type="s:String">
<s:String>No hacer nada</s:String>
<s:String>Abrir el calendario Aero</s:String>
<s:String>Abrir el calendario Moderno</s:String>
<s:String>Abrir el Centro de notificaciones</s:String>
</x:Array>
<s:String x:Key="version">Versión {0}</s:String>
<s:String x:Key="visit_on_github">Visitar RetroBar en GitHub</s:String>
<s:String x:Key="taskbar_scale">Escala de barra de tareas</s:String>
Expand Down
13 changes: 11 additions & 2 deletions RetroBar/PropertiesWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,7 @@
ToolTip="{DynamicResource language_tip}" />
</Label>
<ComboBox Name="cboLanguageSelect"
SelectedValue="{Binding Source={x:Static Settings:Settings.Instance}, Path=Language, UpdateSourceTrigger=PropertyChanged}"
SelectionChanged="cboLanguageSelect_SelectionChanged" />
SelectedValue="{Binding Source={x:Static Settings:Settings.Instance}, Path=Language, UpdateSourceTrigger=PropertyChanged}" />
</DockPanel>
<DockPanel>
<Label VerticalAlignment="Center"
Expand Down Expand Up @@ -366,6 +365,16 @@
SelectedIndex="{Binding Source={x:Static Settings:Settings.Instance}, Path=TaskMiddleClickAction, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource enumConverter}}"
SelectionChanged="cboMiddleMouseAction_SelectionChanged" />
</DockPanel>
<DockPanel>
<Label VerticalAlignment="Center"
Target="{Binding ElementName=cboClockAction}">
<AccessText Text="{DynamicResource clock_click_action}" />
</Label>
<ComboBox x:Name="cboClockAction"
ItemsSource="{DynamicResource clock_click_action_values}"
SelectedIndex="{Binding Source={x:Static Settings:Settings.Instance}, Path=ClockClickAction, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource enumConverter}}"
SelectionChanged="cboClockAction_SelectionChanged" />
</DockPanel>
<DockPanel>
<Label VerticalAlignment="Center"
Target="{Binding ElementName=cboInvertIconsMode}">
Expand Down
34 changes: 31 additions & 3 deletions RetroBar/PropertiesWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ private PropertiesWindow(NotificationArea notificationArea, DictionaryManager di
LoadOSSupport();
LoadRows();
LoadThemes();
LoadVersion();
LoadWidth();
LoadVersion();
LoadClockActions();

Settings.Instance.PropertyChanged += Settings_PropertyChanged;
}
Expand All @@ -98,6 +99,11 @@ private void Settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
LoadPreviewHeight();
}
else if (e.PropertyName == nameof(Settings.Language))
{
LoadVersion();
LoadClockActions();
}
}

public static PropertiesWindow Open(NotificationArea notificationArea, DictionaryManager dictionaryManager, AppBarScreen screen, double dpiScale, double barSize)
Expand Down Expand Up @@ -283,9 +289,23 @@ private void AutoStartCheckBox_OnChecked(object sender, RoutedEventArgs e)
}
}

private void cboLanguageSelect_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
private void LoadClockActions()
{
LoadVersion();
if (EnvironmentHelper.IsWindows10OrBetter)
{
return;
}

// Remove options unsupported prior to Windows 10.
var availableClockActions = (FindResource("clock_click_action_values") as Array)?.Cast<object>().ToList();
if (availableClockActions == null)
{
return;
}

availableClockActions.RemoveAt((int)ClockClickOption.OpenNotificationCenter);
availableClockActions.RemoveAt((int)ClockClickOption.OpenModernCalendar);
cboClockAction.ItemsSource = availableClockActions;
}

private void cboEdgeSelect_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
Expand Down Expand Up @@ -320,6 +340,14 @@ private void cboMiddleMouseAction_SelectionChanged(object sender, System.Windows
}
}

private void cboClockAction_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (cboClockAction.SelectedItem == null)
{
cboClockAction.SelectedValue = cboClockAction.Items[(int)Settings.Instance.ClockClickAction];
}
}

private void cboRowCount_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (cboRowCount.SelectedItem == null)
Expand Down
2 changes: 1 addition & 1 deletion RetroBar/RetroBar.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

<ItemGroup>
<PackageReference Include="gong-wpf-dragdrop" Version="3.1.1" />
<PackageReference Include="ManagedShell" Version="0.0.277" />
<PackageReference Include="ManagedShell" Version="0.0.282" />
<PackageReference Include="System.Net.Http.Json" Version="6.0.2" />
</ItemGroup>

Expand Down
99 changes: 99 additions & 0 deletions RetroBar/Utilities/ClockFlyoutLauncher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Runtime.InteropServices;
using ManagedShell.Common.Helpers;
using static ManagedShell.Interop.NativeMethods;
using Screen = System.Windows.Forms.Screen;

namespace RetroBar.Utilities
{
internal class ClockFlyoutLauncher
{
private const SetWindowPosFlags NoPosFlags = SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOZORDER;

private static readonly Lazy<Type> AeroClockType = new(() => Type.GetTypeFromCLSID(new("A323554A-0FE1-4E49-AEE1-6722465D799F")));
private static object _aeroClockInstance;

[ComImport, Guid("7A5FCA8A-76B1-44C8-A97C-E7173CCA5F4F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAeroClock // For 8+
{
[PreserveSig]
void ShowFlyout(IntPtr hWnd, ref Rect lpRect);
}

[ComImport, Guid("4376DF10-A662-420B-B30D-958881461EF9"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAeroClockLegacy // For Vista and 7
{
[PreserveSig]
void ShowFlyout(int unk, ref Rect lpRect);
}

internal static void ShowAeroClockFlyout(IntPtr taskbarHwnd)
{
Screen taskbarScreen = Screen.FromHandle(taskbarHwnd);
if (!GetWindowRect(taskbarHwnd, out Rect lpRect))
{
return;
}

_aeroClockInstance ??= Activator.CreateInstance(AeroClockType.Value);

if (EnvironmentHelper.IsWindows8OrBetter)
{
((IAeroClock)_aeroClockInstance).ShowFlyout(taskbarHwnd, ref lpRect);
}
else
{
((IAeroClockLegacy)_aeroClockInstance).ShowFlyout(0, ref lpRect);
}

FixAeroClockFlyoutPosition(taskbarScreen);
}

private static void FixAeroClockFlyoutPosition(Screen taskbarScreen)
{
IntPtr clockFlyoutHwnd = FindWindow("ClockFlyoutWindow", null);
if (clockFlyoutHwnd == IntPtr.Zero)
{
return;
}

if (!GetWindowRect(clockFlyoutHwnd, out Rect rect))
{
return;
}

var wa = taskbarScreen.WorkingArea;
int newX = rect.Left, newY = rect.Top;

// Max margin (as used in Windows 7)
int snap = 15;
// Vista margin
int margin = 7;

// Move to closest edge if the flyout is too close to the screen edge
if (Math.Abs(newX - wa.Left) <= snap) // Left
{
newX = wa.Left + margin;
}
else if (Math.Abs(rect.Right - wa.Right) <= snap) // Right
{
newX = wa.Right - rect.Width - margin;
}

if (Math.Abs(newY - wa.Top) <= snap) // Top
{
newY = wa.Top + margin;
}
else if (Math.Abs(rect.Bottom - wa.Bottom) <= snap) // Bottom
{
newY = wa.Bottom - rect.Height - margin;
}

// Keep the flyout inside the working area
newX = Math.Max(wa.Left + margin, Math.Min(newX, wa.Right - rect.Width - margin));
newY = Math.Max(wa.Top + margin, Math.Min(newY, wa.Bottom - rect.Height - margin));

SetWindowPos(clockFlyoutHwnd, IntPtr.Zero, newX, newY, 0, 0, (int)NoPosFlags);
}
}
}
24 changes: 24 additions & 0 deletions RetroBar/Utilities/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,22 @@ public TaskMiddleClickOption TaskMiddleClickAction
set => SetEnum(ref _taskMiddleClickAction, value);
}

private ClockClickOption _clockClickAction = EnvironmentHelper.IsWindows10OrBetter ? ClockClickOption.OpenNotificationCenter : ClockClickOption.DoNothing;
public ClockClickOption ClockClickAction
{
get
{
// On Windows versions prior to 10, neither the Modern calendar nor the Notification Center is available
if (!EnvironmentHelper.IsWindows10OrBetter && _clockClickAction > ClockClickOption.OpenAeroCalendar)
{
return ClockClickOption.DoNothing;
}

return _clockClickAction;
}
set => SetEnum(ref _clockClickAction, value);
}

private bool _checkForUpdates = true;
public bool CheckForUpdates
{
Expand Down Expand Up @@ -390,6 +406,14 @@ public enum TaskMiddleClickOption
CloseTask
}

public enum ClockClickOption
{
DoNothing,
OpenAeroCalendar,
OpenModernCalendar,
OpenNotificationCenter,
}

public enum NotifyIconBehavior
{
HideWhenInactive,
Expand Down
Loading

0 comments on commit 7539928

Please sign in to comment.