Skip to content

Commit c3371d6

Browse files
authored
Fix tray app display name branding (#946)
Align tray app display identity across runtime AppUserModelID, executable metadata, installer shortcut AUMIDs, manifest identity, and approval/permission popup titles so Windows surfaces show OpenClaw Companion instead of OpenClaw.Tray.WinUI. Validation: local build.ps1, Shared tests, Tray tests; GitHub Build and Test, CodeQL, Socket checks all passed. Local proof confirmed built FileDescription/ProductName, installer AUMID declarations, manifest identity, and live OpenClaw Companion app/window identity.
1 parent 02f2421 commit c3371d6

17 files changed

Lines changed: 197 additions & 26 deletions

installer.iss

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
; Pass /DDevBuild=1 to produce a side-by-side dev installer.
33
#ifdef DevBuild
44
#define MyAppName "OpenClaw Companion (Dev)"
5+
#define MyAppAumid "OpenClaw.Companion.Dev"
56
#define MyAppId "{{M0LTB0T-TRAY-4PP1-DEV}"
67
#define MyInstallDir "OpenClawTray-Dev"
78
#define MyMutex "OpenClawTray-Dev"
@@ -12,6 +13,7 @@
1213
#define MyOutputSuffix "-Dev"
1314
#else
1415
#define MyAppName "OpenClaw Companion"
16+
#define MyAppAumid "OpenClaw.Companion"
1517
#define MyAppId "{{M0LTB0T-TRAY-4PP1-D3N7}"
1618
#define MyInstallDir "OpenClawTray"
1719
#define MyMutex "OpenClawTray"
@@ -112,14 +114,14 @@ Root: HKCU; Subkey: "Software\Classes\{#MyProtocol}\DefaultIcon"; ValueType: str
112114
Root: HKCU; Subkey: "Software\Classes\{#MyProtocol}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
113115

114116
[Icons]
115-
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
116-
Name: "{group}\OpenClaw Gateway Setup"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://setup"; IconFilename: "{app}\{#MyAppExeName}"
117-
Name: "{group}\OpenClaw Companion Settings"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://commandcenter"; IconFilename: "{app}\{#MyAppExeName}"
118-
Name: "{group}\OpenClaw Chat"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://chat"; IconFilename: "{app}\{#MyAppExeName}"
119-
Name: "{group}\Check for Updates"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://check-updates"; IconFilename: "{app}\{#MyAppExeName}"
117+
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; AppUserModelID: "{#MyAppAumid}"
118+
Name: "{group}\OpenClaw Gateway Setup"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://setup"; IconFilename: "{app}\{#MyAppExeName}"; AppUserModelID: "{#MyAppAumid}"
119+
Name: "{group}\OpenClaw Companion Settings"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://commandcenter"; IconFilename: "{app}\{#MyAppExeName}"; AppUserModelID: "{#MyAppAumid}"
120+
Name: "{group}\OpenClaw Chat"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://chat"; IconFilename: "{app}\{#MyAppExeName}"; AppUserModelID: "{#MyAppAumid}"
121+
Name: "{group}\Check for Updates"; Filename: "{app}\{#MyAppExeName}"; Parameters: "{#MyProtocol}://check-updates"; IconFilename: "{app}\{#MyAppExeName}"; AppUserModelID: "{#MyAppAumid}"
120122
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
121-
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
122-
Name: "{userstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startupicon
123+
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon; AppUserModelID: "{#MyAppAumid}"
124+
Name: "{userstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startupicon; AppUserModelID: "{#MyAppAumid}"
123125

124126
[Run]
125127
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent; Check: ShouldLaunchTray

src/OpenClaw.Tray.WinUI/App.xaml.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,12 @@ private async Task OnLaunchedAsync(LaunchActivatedEventArgs args)
475475
// Store protocol URI for processing after setup
476476
_pendingProtocolUri = protocolUri;
477477

478+
var appUserModelIdRegistration = AppUserModelIdRegistrar.RegisterCurrentProcess(AppIdentity.AppUserModelId);
479+
if (appUserModelIdRegistration.Attempted && appUserModelIdRegistration.HResult < 0)
480+
{
481+
Logger.Warn($"Failed to set AppUserModelID '{AppIdentity.AppUserModelId}' (HRESULT=0x{appUserModelIdRegistration.HResult:X8}); toast sender name may fall back to the executable name.");
482+
}
483+
478484
// Initialize settings before update check so skip selections can be remembered.
479485
_settings = new SettingsManager();
480486
_previousSettingsSnapshot = _settings.ToSettingsData().ToConnectionSnapshot();

src/OpenClaw.Tray.WinUI/AppIdentity.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ internal static class AppIdentity
1616
/// <summary>MSIX package identity name (must differ from release for side-by-side).</summary>
1717
public const string PackageIdentityName = "OpenClaw.Companion.Dev";
1818

19+
/// <summary>Win32 AppUserModelID used for notifications and shell grouping.</summary>
20+
public const string AppUserModelId = PackageIdentityName;
21+
1922
/// <summary>Windows Registry auto-start value name (must differ so both can auto-start).</summary>
2023
public const string AutoStartRegistryName = "OpenClawTray-Dev";
2124

@@ -52,6 +55,9 @@ internal static class AppIdentity
5255
/// <summary>MSIX package identity name.</summary>
5356
public const string PackageIdentityName = "OpenClaw.Companion";
5457

58+
/// <summary>Win32 AppUserModelID used for notifications and shell grouping.</summary>
59+
public const string AppUserModelId = PackageIdentityName;
60+
5561
/// <summary>Windows Registry auto-start value name.</summary>
5662
public const string AutoStartRegistryName = "OpenClawTray";
5763

src/OpenClaw.Tray.WinUI/Dialogs/PairingApprovalDialog.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public PairingApprovalDialog(PairingApprovalCoordinator coordinator)
5555
{
5656
_coordinator = coordinator ?? throw new ArgumentNullException(nameof(coordinator));
5757

58-
Title = LocalizationHelper.GetString("PairingApproval_WindowTitle");
58+
var windowTitle = $"{AppIdentity.DisplayName} - {LocalizationHelper.GetString("PairingApproval_WindowTitle")}";
59+
Title = windowTitle;
5960
this.SetWindowSize(460, 460);
6061
this.CenterOnScreen();
6162
this.SetIcon("Assets\\openclaw.ico");
@@ -71,7 +72,7 @@ public PairingApprovalDialog(PairingApprovalCoordinator coordinator)
7172
titleBar.Children.Add(titleIcon);
7273
var titleText = new TextBlock
7374
{
74-
Text = LocalizationHelper.GetString("PairingApproval_WindowTitle"),
75+
Text = windowTitle,
7576
FontSize = 13,
7677
VerticalAlignment = VerticalAlignment.Center,
7778
Style = (Style)Application.Current.Resources["CaptionTextBlockStyle"],

src/OpenClaw.Tray.WinUI/Dialogs/RecordingConsentDialog.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ public RecordingConsentDialog(RecordingType type)
3939
var descriptionKey = isScreen ? "RecordingConsent_ScreenDescription" : "RecordingConsent_CameraDescription";
4040
var emoji = isScreen ? "🖥️" : "📷";
4141

42-
Title = LocalizationHelper.GetString("RecordingConsent_WindowTitle");
42+
var windowTitle = $"{AppIdentity.DisplayName} - {LocalizationHelper.GetString("RecordingConsent_WindowTitle")}";
43+
Title = windowTitle;
4344
this.SetWindowSize(460, 340);
4445
this.CenterOnScreen();
4546
this.SetIcon("Assets\\openclaw.ico");
@@ -67,7 +68,7 @@ public RecordingConsentDialog(RecordingType type)
6768

6869
var titleText = new TextBlock
6970
{
70-
Text = LocalizationHelper.GetString("RecordingConsent_WindowTitle"),
71+
Text = windowTitle,
7172
FontSize = 13,
7273
VerticalAlignment = VerticalAlignment.Center,
7374
Style = (Style)Application.Current.Resources["CaptionTextBlockStyle"]

src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
<Nullable>enable</Nullable>
99
<EnableMsixTooling>true</EnableMsixTooling>
1010
<ApplicationIcon>Assets\openclaw.ico</ApplicationIcon>
11+
<AssemblyTitle>OpenClaw Companion</AssemblyTitle>
12+
<FileDescription>OpenClaw Companion</FileDescription>
13+
<Product>OpenClaw Companion</Product>
1114
<RootNamespace>OpenClawTray</RootNamespace>
1215
<DefaultLanguage>en-US</DefaultLanguage>
1316
<Platforms>x64;ARM64</Platforms>
@@ -19,6 +22,9 @@
1922
<PropertyGroup Condition="'$(DevBuild)' == 'true'">
2023
<DefineConstants>$(DefineConstants);DEV_BUILD</DefineConstants>
2124
<AppIdentityMarker>dev</AppIdentityMarker>
25+
<AssemblyTitle>OpenClaw Companion (Dev)</AssemblyTitle>
26+
<FileDescription>OpenClaw Companion (Dev)</FileDescription>
27+
<Product>OpenClaw Companion (Dev)</Product>
2228
</PropertyGroup>
2329
<PropertyGroup Condition="'$(DevBuild)' != 'true'">
2430
<AppIdentityMarker>release</AppIdentityMarker>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Text;
4+
5+
namespace OpenClawTray.Services;
6+
7+
internal readonly record struct AppUserModelIdRegistrationResult(bool Attempted, int HResult);
8+
9+
internal static class AppUserModelIdRegistrar
10+
{
11+
private const int AppModelErrorNoPackage = 15700;
12+
private const int ErrorInsufficientBuffer = 122;
13+
private const int ErrorSuccess = 0;
14+
15+
public static AppUserModelIdRegistrationResult RegisterCurrentProcess(string appUserModelId)
16+
{
17+
ArgumentException.ThrowIfNullOrWhiteSpace(appUserModelId);
18+
if (HasPackageIdentity())
19+
return new AppUserModelIdRegistrationResult(Attempted: false, HResult: ErrorSuccess);
20+
21+
return new AppUserModelIdRegistrationResult(
22+
Attempted: true,
23+
HResult: SetCurrentProcessExplicitAppUserModelID(appUserModelId));
24+
}
25+
26+
private static bool HasPackageIdentity()
27+
{
28+
var packageFullNameLength = 0;
29+
var result = GetCurrentPackageFullName(ref packageFullNameLength, null);
30+
if (result == AppModelErrorNoPackage)
31+
return false;
32+
33+
return result is ErrorSuccess or ErrorInsufficientBuffer;
34+
}
35+
36+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
37+
private static extern int GetCurrentPackageFullName(
38+
ref int packageFullNameLength,
39+
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder? packageFullName);
40+
41+
[DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
42+
private static extern int SetCurrentProcessExplicitAppUserModelID(
43+
[MarshalAs(UnmanagedType.LPWStr)] string appID);
44+
}

src/OpenClaw.Tray.WinUI/Services/ExecApprovalPromptService.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public sealed class ExecApprovalPromptService : IExecApprovalPromptHandler
1515
private readonly IOpenClawLogger _logger;
1616
private readonly Func<OpenClawChatDataProvider?>? _chatProviderProvider;
1717
private readonly Func<string, bool>? _inlineApprovalAvailable;
18+
private static string NativePromptTitle => $"{AppIdentity.DisplayName} - Approve local command?";
1819

1920
public ExecApprovalPromptService(
2021
DispatcherQueue dispatcherQueue,
@@ -161,7 +162,7 @@ private void RaiseDecided(
161162
private static ExecApprovalPromptDecision ShowNativePrompt(ExecApprovalPromptRequest request)
162163
{
163164
var text =
164-
"A remote agent wants to run a local command on this Windows machine." +
165+
$"{AppIdentity.DisplayName} needs approval before a remote agent can run a local command on this Windows machine." +
165166
"\r\n\r\n" +
166167
request.Command +
167168
"\r\n\r\n" +
@@ -190,7 +191,7 @@ private static ExecApprovalPromptDecision ShowMessageBoxFallback(string text)
190191
var result = MessageBoxW(
191192
IntPtr.Zero,
192193
fallbackText,
193-
"Approve local command?",
194+
NativePromptTitle,
194195
MessageBoxFlags.YesNoCancel |
195196
MessageBoxFlags.IconWarning |
196197
MessageBoxFlags.TopMost |
@@ -263,7 +264,7 @@ public ExecApprovalPromptDecision Show()
263264
_hwnd = CreateWindowExW(
264265
WindowExStyleTopMost | WindowExStyleDialogModalFrame,
265266
WindowClassName,
266-
"Approve local command?",
267+
NativePromptTitle,
267268
WindowStyleCaption | WindowStyleSystemMenu | WindowStyleVisible,
268269
x,
269270
y,
@@ -341,7 +342,7 @@ private static void EnsureClassRegistered()
341342
private void CreateControls(IntPtr hwnd)
342343
{
343344
var font = GetStockObject(DefaultGuiFont);
344-
CreateChild(hwnd, "STATIC", "Approve local command?", 20, 18, 590, 24, StaticStyleLeft, 0, font);
345+
CreateChild(hwnd, "STATIC", NativePromptTitle, 20, 18, 590, 24, StaticStyleLeft, 0, font);
345346
CreateChild(
346347
hwnd,
347348
"EDIT",

src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,7 @@ Use one of these options:
832832
</data>
833833
<!-- ==================== Recording Consent Dialog ==================== -->
834834
<data name="RecordingConsent_WindowTitle" xml:space="preserve">
835-
<value>OpenClaw · Permission Request</value>
835+
<value>Permission Request</value>
836836
</data>
837837
<data name="RecordingConsent_ScreenTitle" xml:space="preserve">
838838
<value>Allow screen recording?</value>

src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ Utilisez l'une de ces options :
789789
</data>
790790
<!-- ==================== Recording Consent Dialog ==================== -->
791791
<data name="RecordingConsent_WindowTitle" xml:space="preserve">
792-
<value>OpenClaw · Demande d'autorisation</value>
792+
<value>Demande d'autorisation</value>
793793
</data>
794794
<data name="RecordingConsent_ScreenTitle" xml:space="preserve">
795795
<value>Autoriser l'enregistrement d'écran ?</value>

0 commit comments

Comments
 (0)