From 0580942a59b9ec136ea1e01e0b923be7451e9d81 Mon Sep 17 00:00:00 2001 From: softworkz Date: Fri, 14 Nov 2025 09:44:01 +0100 Subject: [PATCH 1/3] ElectronNET API: Add platform support attributes --- src/ElectronNET.API/API/App.cs | 42 +++++++++++ src/ElectronNET.API/API/BrowserWindow.cs | 70 ++++++++++++++++++- src/ElectronNET.API/API/Clipboard.cs | 7 ++ src/ElectronNET.API/API/Dialog.cs | 5 ++ src/ElectronNET.API/API/Dock.cs | 8 +-- .../API/Entities/NotificationOptions.cs | 8 ++- src/ElectronNET.API/API/NativeTheme.cs | 7 +- src/ElectronNET.API/API/PowerMonitor.cs | 13 +++- src/ElectronNET.API/API/Screen.cs | 2 + src/ElectronNET.API/API/Shell.cs | 7 +- src/ElectronNET.API/API/Tray.cs | 11 +++ 11 files changed, 167 insertions(+), 13 deletions(-) diff --git a/src/ElectronNET.API/API/App.cs b/src/ElectronNET.API/API/App.cs index 1c1ffc56..c486f90a 100644 --- a/src/ElectronNET.API/API/App.cs +++ b/src/ElectronNET.API/API/App.cs @@ -2,6 +2,7 @@ using ElectronNET.API.Extensions; using System; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -259,6 +260,8 @@ public event Action WebContentsCreated /// screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details. /// /// when Chrome's accessibility support is enabled, otherwise. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action AccessibilitySupportChanged { add => AddEvent(value, GetHashCode()); @@ -316,6 +319,7 @@ internal set /// /// On Windows, you have to parse the arguments using App.CommandLine to get the filepath. /// + [SupportedOSPlatform("macOS")] public event Action OpenFile { add => AddEvent(value, GetHashCode()); @@ -327,6 +331,7 @@ public event Action OpenFile /// Emitted when a MacOS user wants to open a URL with the application. Your application's Info.plist file must /// define the URL scheme within the CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication. /// + [SupportedOSPlatform("macOS")] public event Action OpenUrl { add => AddEvent(value, GetHashCode()); @@ -481,6 +486,7 @@ public void Focus(FocusOptions focusOptions) /// /// Hides all application windows without minimizing them. /// + [SupportedOSPlatform("macOS")] public void Hide() { this.CallMethod0(); @@ -489,6 +495,7 @@ public void Hide() /// /// Shows application windows after they were hidden. Does not automatically focus them. /// + [SupportedOSPlatform("macOS")] public void Show() { this.CallMethod0(); @@ -586,6 +593,8 @@ public async Task GetLocaleAsync(CancellationToken cancellationToken = d /// list from the task bar, and on macOS you can visit it from dock menu. /// /// Path to add. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void AddRecentDocument(string path) { this.CallMethod1(path); @@ -594,6 +603,8 @@ public void AddRecentDocument(string path) /// /// Clears the recent documents list. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void ClearRecentDocuments() { this.CallMethod0(); @@ -709,6 +720,8 @@ public async Task SetAsDefaultProtocolClientAsync(string protocol, string /// The name of your protocol, without ://. /// The cancellation token. /// Whether the call succeeded. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public async Task RemoveAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default) { return await this.RemoveAsDefaultProtocolClientAsync(protocol, null, null, cancellationToken).ConfigureAwait(false); @@ -722,6 +735,8 @@ public async Task RemoveAsDefaultProtocolClientAsync(string protocol, Canc /// Defaults to process.execPath. /// The cancellation token. /// Whether the call succeeded. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public async Task RemoveAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default) { return await this.RemoveAsDefaultProtocolClientAsync(protocol, path, null, cancellationToken).ConfigureAwait(false); @@ -736,6 +751,8 @@ public async Task RemoveAsDefaultProtocolClientAsync(string protocol, stri /// Defaults to an empty array. /// The cancellation token. /// Whether the call succeeded. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public async Task RemoveAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -826,6 +843,7 @@ public async Task IsDefaultProtocolClientAsync(string protocol, string pat /// Array of objects. /// The cancellation token. /// Whether the call succeeded. + [SupportedOSPlatform("Windows")] public async Task SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -846,6 +864,7 @@ public async Task SetUserTasksAsync(UserTask[] userTasks, CancellationToke /// /// The cancellation token. /// Jump List settings. + [SupportedOSPlatform("Windows")] public async Task GetJumpListSettingsAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -868,6 +887,7 @@ public async Task GetJumpListSettingsAsync(CancellationToken c /// omitted from the Jump List. The list of removed items can be obtained using . /// /// Array of objects. + [SupportedOSPlatform("Windows")] public void SetJumpList(JumpListCategory[] categories) { this.CallMethod1(categories); @@ -950,6 +970,7 @@ public async Task HasSingleInstanceLockAsync(CancellationToken cancellatio /// /// Uniquely identifies the activity. Maps to NSUserActivity.activityType. /// App-specific state to store for use by another device. + [SupportedOSPlatform("macOS")] public void SetUserActivity(string type, object userInfo) { SetUserActivity(type, userInfo, null); @@ -967,6 +988,7 @@ public void SetUserActivity(string type, object userInfo) /// /// The webpage to load in a browser if no suitable app is installed on the resuming device. The scheme must be http or https. /// + [SupportedOSPlatform("macOS")] public void SetUserActivity(string type, object userInfo, string webpageUrl) { this.CallMethod3(type, userInfo, webpageUrl); @@ -976,6 +998,7 @@ public void SetUserActivity(string type, object userInfo, string webpageUrl) /// The type of the currently running activity. /// /// The cancellation token. + [SupportedOSPlatform("macOS")] public async Task GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -985,6 +1008,7 @@ public async Task GetCurrentActivityTypeAsync(CancellationToken cancella /// /// Invalidates the current Handoff user activity. /// + [SupportedOSPlatform("macOS")] public void InvalidateCurrentActivity() { this.CallMethod0(); @@ -993,6 +1017,7 @@ public void InvalidateCurrentActivity() /// /// Marks the current Handoff user activity as inactive without invalidating it. /// + [SupportedOSPlatform("macOS")] public void ResignCurrentActivity() { this.CallMethod0(); @@ -1002,6 +1027,7 @@ public void ResignCurrentActivity() /// Changes the Application User Model ID to id. /// /// Model Id. + [SupportedOSPlatform("Windows")] public void SetAppUserModelId(string id) { this.CallMethod1(id); @@ -1016,6 +1042,7 @@ public void SetAppUserModelId(string id) /// /// The cancellation token. /// Result of import. Value of 0 indicates success. + [SupportedOSPlatform("Linux")] public async Task ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -1067,6 +1094,8 @@ public async Task GetGpuFeatureStatusAsync(CancellationToken c /// Counter badge. /// The cancellation token. /// Whether the call succeeded. + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("macOS")] public async Task SetBadgeCountAsync(int count, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -1086,6 +1115,8 @@ public async Task SetBadgeCountAsync(int count, CancellationToken cancella /// The current value displayed in the counter badge. /// /// The cancellation token. + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("macOS")] public async Task GetBadgeCountAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -1101,6 +1132,7 @@ public async Task GetBadgeCountAsync(CancellationToken cancellationToken = /// Whether the current desktop environment is Unity launcher. /// /// The cancellation token. + [SupportedOSPlatform("Linux")] public async Task IsUnityRunningAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -1111,6 +1143,8 @@ public async Task IsUnityRunningAsync(CancellationToken cancellationToken /// If you provided path and args options to then you need to pass the same /// arguments here for to be set correctly. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public async Task GetLoginItemSettingsAsync(CancellationToken cancellationToken = default) { return await this.GetLoginItemSettingsAsync(null, cancellationToken).ConfigureAwait(false); @@ -1122,6 +1156,8 @@ public async Task GetLoginItemSettingsAsync(CancellationToken /// /// /// The cancellation token. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public async Task GetLoginItemSettingsAsync(LoginItemSettingsOptions options, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -1151,6 +1187,8 @@ public async Task GetLoginItemSettingsAsync(LoginItemSettings /// you'll want to set the launch path to Update.exe, and pass arguments that specify your application name. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetLoginItemSettings(LoginSettings loginSettings) { this.CallMethod1(loginSettings); @@ -1162,6 +1200,8 @@ public void SetLoginItemSettings(LoginSettings loginSettings) /// See Chromium's accessibility docs for more details. /// /// if Chrome’s accessibility support is enabled, otherwise. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public async Task IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -1178,6 +1218,8 @@ public async Task IsAccessibilitySupportEnabledAsync(CancellationToken can /// Note: Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. /// /// Enable or disable accessibility tree rendering. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetAccessibilitySupportEnabled(bool enabled) { this.CallMethod1(enabled); diff --git a/src/ElectronNET.API/API/BrowserWindow.cs b/src/ElectronNET.API/API/BrowserWindow.cs index 67f8b969..bd60b77d 100644 --- a/src/ElectronNET.API/API/BrowserWindow.cs +++ b/src/ElectronNET.API/API/BrowserWindow.cs @@ -1,10 +1,11 @@ -using ElectronNET.API.Entities; -using ElectronNET.API.Extensions; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading.Tasks; +using ElectronNET.API.Entities; +using ElectronNET.API.Extensions; // ReSharper disable InconsistentNaming @@ -68,6 +69,7 @@ public event Action OnClosed /// /// Emitted when window session is going to end due to force shutdown or machine restart or session log off. /// + [SupportedOSPlatform("Windows")] public event Action OnSessionEnd { add => AddEvent(value, Id); @@ -187,6 +189,8 @@ public event Action OnMove /// /// macOS: Emitted once when the window is moved to a new position. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action OnMoved { add => AddEvent(value, Id); @@ -238,6 +242,8 @@ public event Action OnLeaveHtmlFullScreen /// and the APPCOMMAND_ prefix is stripped off.e.g.APPCOMMAND_BROWSER_BACKWARD /// is emitted as browser-backward. /// + [SupportedOSPlatform("Windows")] + [SupportedOSPlatform("Linux")] public event Action OnAppCommand { add => AddEvent(value, Id); @@ -247,6 +253,7 @@ public event Action OnAppCommand /// /// Emitted on 3-finger swipe. Possible directions are up, right, down, left. /// + [SupportedOSPlatform("macOS")] public event Action OnSwipe { add => AddEvent(value, Id); @@ -256,6 +263,7 @@ public event Action OnSwipe /// /// Emitted when the window opens a sheet. /// + [SupportedOSPlatform("macOS")] public event Action OnSheetBegin { add => AddEvent(value, Id); @@ -265,6 +273,7 @@ public event Action OnSheetBegin /// /// Emitted when the window has closed a sheet. /// + [SupportedOSPlatform("macOS")] public event Action OnSheetEnd { add => AddEvent(value, Id); @@ -274,6 +283,7 @@ public event Action OnSheetEnd /// /// Emitted when the native new tab button is clicked. /// + [SupportedOSPlatform("macOS")] public event Action OnNewWindowForTab { add => AddEvent(value, Id); @@ -432,6 +442,7 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// The absolute path to the file to preview with QuickLook. This is important as /// Quick Look uses the file name and file extension on the path to determine the content type of the /// file to open. + [SupportedOSPlatform("macOS")] public void PreviewFile(string path) => this.CallMethod1(path); /// @@ -442,11 +453,13 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// file to open. /// The name of the file to display on the Quick Look modal view. This is /// purely visual and does not affect the content type of the file. Defaults to path. + [SupportedOSPlatform("macOS")] public void PreviewFile(string path, string displayname) => this.CallMethod2(path, displayname); /// /// Closes the currently open Quick Look panel. /// + [SupportedOSPlatform("macOS")] public void CloseFilePreview() => this.CallMethod0(); /// @@ -571,6 +584,8 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// Sets whether the window can be moved by user. On Linux does nothing. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetMovable(bool movable) => this.CallMethod1(movable); /// @@ -579,12 +594,16 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// On Linux always returns true. /// /// On Linux always returns true. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task IsMovableAsync() => this.InvokeAsync(); /// /// Sets whether the window can be manually minimized by user. On Linux does nothing. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetMinimizable(bool minimizable) => this.CallMethod1(minimizable); /// @@ -593,12 +612,16 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// On Linux always returns true. /// /// On Linux always returns true. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task IsMinimizableAsync() => this.InvokeAsync(); /// /// Sets whether the window can be manually maximized by user. On Linux does nothing. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetMaximizable(bool maximizable) => this.CallMethod1(maximizable); /// @@ -607,6 +630,8 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// On Linux always returns true. /// /// On Linux always returns true. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task IsMaximizableAsync() => this.InvokeAsync(); /// @@ -625,6 +650,8 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// Sets whether the window can be manually closed by user. On Linux does nothing. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetClosable(bool closable) => this.CallMethod1(closable); /// @@ -633,6 +660,8 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) => /// On Linux always returns true. /// /// On Linux always returns true. + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task IsClosableAsync() => this.InvokeAsync(); /// @@ -743,6 +772,7 @@ private bool isWindows10() /// but you may want to display them beneath a HTML-rendered toolbar. /// /// + [SupportedOSPlatform("macOS")] public void SetSheetOffset(float offsetY) => this.CallMethod1(offsetY); /// @@ -752,6 +782,7 @@ private bool isWindows10() /// /// /// + [SupportedOSPlatform("macOS")] public void SetSheetOffset(float offsetY, float offsetX) => this.CallMethod2(offsetY, offsetX); /// @@ -764,6 +795,8 @@ private bool isWindows10() /// Makes the window not show in the taskbar. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetSkipTaskbar(bool skip) => this.CallMethod1(skip); /// @@ -789,12 +822,14 @@ private bool isWindows10() /// and the icon of the file will show in window’s title bar. /// /// + [SupportedOSPlatform("macOS")] public void SetRepresentedFilename(string filename) => this.CallMethod1(filename); /// /// The pathname of the file the window represents. /// /// + [SupportedOSPlatform("macOS")] public Task GetRepresentedFilenameAsync() => this.InvokeAsync(); /// @@ -802,12 +837,14 @@ private bool isWindows10() /// and the icon in title bar will become gray when set to true. /// /// + [SupportedOSPlatform("macOS")] public void SetDocumentEdited(bool edited) => this.CallMethod1(edited); /// /// Whether the window’s document has been edited. /// /// + [SupportedOSPlatform("macOS")] public Task IsDocumentEditedAsync() => this.InvokeAsync(); /// @@ -861,6 +898,8 @@ public IReadOnlyCollection MenuItems /// setting it to null will remove the menu bar. /// /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("Windows")] public void SetMenu(MenuItem[] menuItems) { menuItems.AddMenuItemsId(); @@ -878,6 +917,8 @@ public void SetMenu(MenuItem[] menuItems) /// /// Remove the window's menu bar. /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("Windows")] public void RemoveMenu() => this.CallMethod0(); /// @@ -950,6 +991,7 @@ public IReadOnlyCollection ThumbarButtons /// /// /// Whether the buttons were added successfully. + [SupportedOSPlatform("Windows")] public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) { var tcs = new TaskCompletionSource(); @@ -977,12 +1019,14 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// an empty region: {x: 0, y: 0, width: 0, height: 0}. /// /// + [SupportedOSPlatform("Windows")] public void SetThumbnailClip(Rectangle rectangle) => this.CallMethod1(rectangle); /// /// Sets the toolTip that is displayed when hovering over the window thumbnail in the taskbar. /// /// + [SupportedOSPlatform("Windows")] public void SetThumbnailToolTip(string tooltip) => this.CallMethod1(tooltip); /// @@ -992,11 +1036,13 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// If one of those properties is not set, then neither will be used. /// /// + [SupportedOSPlatform("Windows")] public void SetAppDetails(AppDetailsOptions options) => this.CallMethod1(options); /// /// Same as webContents.showDefinitionForSelection(). /// + [SupportedOSPlatform("macOS")] public void ShowDefinitionForSelection() => this.CallMethod0(); /// @@ -1006,12 +1052,16 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// If the menu bar is already visible, calling setAutoHideMenuBar(true) won’t hide it immediately. /// /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("Windows")] public void SetAutoHideMenuBar(bool hide) => this.CallMethod1(hide); /// /// Whether menu bar automatically hides itself. /// /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("Windows")] public Task IsMenuBarAutoHideAsync() => this.InvokeAsync(); /// @@ -1019,12 +1069,16 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// users can still bring up the menu bar by pressing the single Alt key. /// /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("Windows")] public void SetMenuBarVisibility(bool visible) => this.CallMethod1(visible); /// /// Whether the menu bar is visible. /// /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("Windows")] public Task IsMenuBarVisibleAsync() => this.InvokeAsync(); /// @@ -1033,6 +1087,8 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// Note: This API does nothing on Windows. /// /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("macOS")] public void SetVisibleOnAllWorkspaces(bool visible) => this.CallMethod1(visible); /// @@ -1041,6 +1097,8 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// Note: This API always returns false on Windows. /// /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("macOS")] public Task IsVisibleOnAllWorkspacesAsync() => this.InvokeAsync(); /// @@ -1059,12 +1117,16 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// On Windows it calls SetWindowDisplayAffinity with WDA_MONITOR. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetContentProtection(bool enable) => this.CallMethod1(enable); /// /// Changes whether the window can be focused. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void SetFocusable(bool focusable) => this.CallMethod1(focusable); /// @@ -1117,6 +1179,7 @@ public async Task> GetChildWindowsAsync() /// Controls whether to hide cursor when typing. /// /// + [SupportedOSPlatform("macOS")] public void SetAutoHideCursor(bool autoHide) => this.CallMethod1(autoHide); /// @@ -1126,6 +1189,7 @@ public async Task> GetChildWindowsAsync() /// Can be appearance-based, light, dark, titlebar, selection, /// menu, popover, sidebar, medium-light or ultra-dark. /// See the macOS documentation for more details. + [SupportedOSPlatform("macOS")] public void SetVibrancy(Vibrancy type) => this.CallMethod1(type.GetDescription()); /// @@ -1144,4 +1208,4 @@ public void SetBrowserView(BrowserView browserView) // This message name does not match the default ApiBase naming convention. BridgeConnector.Socket.Emit("browserWindow-setBrowserView", Id, browserView.Id); } -} \ No newline at end of file +} diff --git a/src/ElectronNET.API/API/Clipboard.cs b/src/ElectronNET.API/API/Clipboard.cs index 4b063275..c25e3dd5 100644 --- a/src/ElectronNET.API/API/Clipboard.cs +++ b/src/ElectronNET.API/API/Clipboard.cs @@ -1,5 +1,6 @@ using ElectronNET.API.Entities; using ElectronNET.API.Serialization; +using System.Runtime.Versioning; using System.Text.Json; using System.Threading.Tasks; @@ -98,6 +99,8 @@ public void WriteRTF(string text, string type = "") /// be empty strings when the bookmark is unavailable. /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task ReadBookmarkAsync() => this.InvokeAsync(); /// @@ -110,6 +113,8 @@ public void WriteRTF(string text, string type = "") /// /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public void WriteBookmark(string title, string url, string type = "") { BridgeConnector.Socket.Emit("clipboard-writeBookmark", title, url, type); @@ -121,6 +126,7 @@ public void WriteBookmark(string title, string url, string type = "") /// find pasteboard whenever the application is activated. /// /// + [SupportedOSPlatform("macOS")] public Task ReadFindTextAsync() => this.InvokeAsync(); /// @@ -128,6 +134,7 @@ public void WriteBookmark(string title, string url, string type = "") /// synchronous IPC when called from the renderer process. /// /// + [SupportedOSPlatform("macOS")] public void WriteFindText(string text) { BridgeConnector.Socket.Emit("clipboard-writeFindText", text); diff --git a/src/ElectronNET.API/API/Dialog.cs b/src/ElectronNET.API/API/Dialog.cs index fa60840c..21816463 100644 --- a/src/ElectronNET.API/API/Dialog.cs +++ b/src/ElectronNET.API/API/Dialog.cs @@ -1,5 +1,6 @@ using ElectronNET.API.Entities; using System; +using System.Runtime.Versioning; using System.Text.Json; using System.Threading.Tasks; @@ -186,6 +187,8 @@ public void ShowErrorBox(string title, string content) /// /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions options) { return ShowCertificateTrustDialogAsync(null, options); @@ -199,6 +202,8 @@ public Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions option /// /// /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options) { var tcs = new TaskCompletionSource(); diff --git a/src/ElectronNET.API/API/Dock.cs b/src/ElectronNET.API/API/Dock.cs index 1e77d211..1186d37a 100644 --- a/src/ElectronNET.API/API/Dock.cs +++ b/src/ElectronNET.API/API/Dock.cs @@ -1,16 +1,16 @@ -using ElectronNET.API.Entities; -using ElectronNET.API.Extensions; -using ElectronNET.API.Serialization; using System.Collections.Generic; -using System.Text.Json; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; +using ElectronNET.API.Entities; +using ElectronNET.API.Extensions; namespace ElectronNET.API { /// /// Control your app in the macOS dock. /// + [SupportedOSPlatform("macOS")] public sealed class Dock { private static Dock _dock; diff --git a/src/ElectronNET.API/API/Entities/NotificationOptions.cs b/src/ElectronNET.API/API/Entities/NotificationOptions.cs index ce9fb680..4093f523 100644 --- a/src/ElectronNET.API/API/Entities/NotificationOptions.cs +++ b/src/ElectronNET.API/API/Entities/NotificationOptions.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Versioning; using System.Text.Json.Serialization; namespace ElectronNET.API.Entities @@ -43,6 +44,8 @@ public class NotificationOptions /// /// The timeout duration of the notification. Can be 'default' or 'never'. /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("Windows")] public string TimeoutType { get; set; } /// @@ -58,6 +61,7 @@ public class NotificationOptions /// /// The urgency level of the notification. Can be 'normal', 'critical', or 'low'. /// + [SupportedOSPlatform("Linux")] public string Urgency { get; set; } /// @@ -127,6 +131,7 @@ public class NotificationOptions /// The string the user entered into the inline reply field /// [JsonIgnore] + [SupportedOSPlatform("macOS")] public Action OnReply { get; set; } /// @@ -142,6 +147,7 @@ public class NotificationOptions /// macOS only - The index of the action that was activated /// [JsonIgnore] + [SupportedOSPlatform("macOS")] public Action OnAction { get; set; } /// @@ -164,4 +170,4 @@ public NotificationOptions(string title, string body) Body = body; } } -} \ No newline at end of file +} diff --git a/src/ElectronNET.API/API/NativeTheme.cs b/src/ElectronNET.API/API/NativeTheme.cs index 0879fe80..71b35cf5 100644 --- a/src/ElectronNET.API/API/NativeTheme.cs +++ b/src/ElectronNET.API/API/NativeTheme.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Versioning; using System.Threading.Tasks; using ElectronNET.API.Entities; using ElectronNET.API.Extensions; @@ -120,12 +121,16 @@ public void SetThemeSource(ThemeSourceMode themeSourceMode) /// A for if the OS / Chromium currently has high-contrast mode enabled or is /// being instructed to show a high-contrast UI. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task ShouldUseHighContrastColorsAsync() => this.InvokeAsync(); /// /// A for if the OS / Chromium currently has an inverted color scheme or is /// being instructed to use an inverted color scheme. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public Task ShouldUseInvertedColorSchemeAsync() => this.InvokeAsync(); /// @@ -138,4 +143,4 @@ public event Action Updated remove => RemoveEvent(value, GetHashCode()); } } -} \ No newline at end of file +} diff --git a/src/ElectronNET.API/API/PowerMonitor.cs b/src/ElectronNET.API/API/PowerMonitor.cs index 5e14dafe..776af480 100644 --- a/src/ElectronNET.API/API/PowerMonitor.cs +++ b/src/ElectronNET.API/API/PowerMonitor.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Versioning; // ReSharper disable InconsistentNaming @@ -15,6 +16,8 @@ public sealed class PowerMonitor : ApiBase /// /// Emitted when the system is about to lock the screen. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action OnLockScreen { add => AddEvent(value); @@ -24,6 +27,8 @@ public event Action OnLockScreen /// /// Emitted when the system is about to unlock the screen. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action OnUnLockScreen { add => AddEvent(value); @@ -51,6 +56,8 @@ public event Action OnResume /// /// Emitted when the system changes to AC power. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action OnAC { add => AddEvent(value); @@ -60,6 +67,8 @@ public event Action OnAC /// /// Emitted when system changes to battery power. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action OnBattery { add => AddEvent(value); @@ -72,6 +81,8 @@ public event Action OnBattery /// order for the app to exit cleanly.If `e.preventDefault()` is called, the app /// should exit as soon as possible by calling something like `app.quit()`. /// + [SupportedOSPlatform("Linux")] + [SupportedOSPlatform("macOS")] public event Action OnShutdown { add => AddEvent(value); @@ -104,4 +115,4 @@ internal static PowerMonitor Instance } } } -} \ No newline at end of file +} diff --git a/src/ElectronNET.API/API/Screen.cs b/src/ElectronNET.API/API/Screen.cs index 65c01079..5c81e583 100644 --- a/src/ElectronNET.API/API/Screen.cs +++ b/src/ElectronNET.API/API/Screen.cs @@ -1,6 +1,7 @@ using ElectronNET.API.Entities; using System; using System.Linq; +using System.Runtime.Versioning; using System.Text.Json; using System.Threading.Tasks; using ElectronNET.API.Serialization; @@ -108,6 +109,7 @@ internal static Screen Instance /// macOS: The height of the menu bar in pixels. /// /// The height of the menu bar in pixels. + [SupportedOSPlatform("macOS")] public Task GetMenuBarWorkAreaAsync() => this.InvokeAsync(); /// diff --git a/src/ElectronNET.API/API/Shell.cs b/src/ElectronNET.API/API/Shell.cs index 3b3d22aa..e8acb0ee 100644 --- a/src/ElectronNET.API/API/Shell.cs +++ b/src/ElectronNET.API/API/Shell.cs @@ -1,8 +1,7 @@ +using System.Runtime.Versioning; +using System.Threading.Tasks; using ElectronNET.API.Entities; using ElectronNET.API.Extensions; -using ElectronNET.API.Serialization; -using System.Text.Json; -using System.Threading.Tasks; namespace ElectronNET.API { @@ -133,6 +132,7 @@ public void Beep() /// Default is /// Structure of a shortcut. /// Whether the shortcut was created successfully. + [SupportedOSPlatform("Windows")] public Task WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options) { var tcs = new TaskCompletionSource(); @@ -149,6 +149,7 @@ public Task WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperat /// /// The path tot the shortcut. /// of the shortcut. + [SupportedOSPlatform("Windows")] public Task ReadShortcutLinkAsync(string shortcutPath) { var tcs = new TaskCompletionSource(); diff --git a/src/ElectronNET.API/API/Tray.cs b/src/ElectronNET.API/API/Tray.cs index ad9bc959..b31edd64 100644 --- a/src/ElectronNET.API/API/Tray.cs +++ b/src/ElectronNET.API/API/Tray.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Versioning; using System.Text.Json; using System.Threading.Tasks; using ElectronNET.API.Serialization; @@ -57,6 +58,8 @@ public event Action OnClick /// /// macOS, Windows: Emitted when the tray icon is right clicked. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action OnRightClick { add @@ -92,6 +95,8 @@ public event Action OnRightClick /// /// macOS, Windows: Emitted when the tray icon is double clicked. /// + [SupportedOSPlatform("macOS")] + [SupportedOSPlatform("Windows")] public event Action OnDoubleClick { add @@ -127,6 +132,7 @@ public event Action OnDoubleClick /// /// Windows: Emitted when the tray balloon shows. /// + [SupportedOSPlatform("Windows")] public event Action OnBalloonShow { add => AddEvent(value, GetHashCode()); @@ -136,6 +142,7 @@ public event Action OnBalloonShow /// /// Windows: Emitted when the tray balloon is clicked. /// + [SupportedOSPlatform("Windows")] public event Action OnBalloonClick { add => AddEvent(value, GetHashCode()); @@ -146,6 +153,7 @@ public event Action OnBalloonClick /// Windows: Emitted when the tray balloon is closed /// because of timeout or user manually closes it. /// + [SupportedOSPlatform("Windows")] public event Action OnBalloonClosed { add => AddEvent(value, GetHashCode()); @@ -251,6 +259,7 @@ public async Task SetImage(string image) /// Sets the image associated with this tray icon when pressed on macOS. /// /// + [SupportedOSPlatform("macOS")] public async Task SetPressedImage(string image) { await BridgeConnector.Socket.Emit("tray-setPressedImage", image).ConfigureAwait(false); @@ -269,6 +278,7 @@ public async Task SetToolTip(string toolTip) /// macOS: Sets the title displayed aside of the tray icon in the status bar. /// /// + [SupportedOSPlatform("macOS")] public async Task SetTitle(string title) { await BridgeConnector.Socket.Emit("tray-setTitle", title).ConfigureAwait(false); @@ -278,6 +288,7 @@ public async Task SetTitle(string title) /// Windows: Displays a tray balloon. /// /// + [SupportedOSPlatform("Windows")] public async Task DisplayBalloon(DisplayBalloonOptions options) { await BridgeConnector.Socket.Emit("tray-displayBalloon", options).ConfigureAwait(false); From 0ec791da9d2ff41a60efe9c13a6ab3da81169f7e Mon Sep 17 00:00:00 2001 From: softworkz Date: Sun, 16 Nov 2025 02:59:50 +0100 Subject: [PATCH 2/3] Improve test Progress_bar_and_always_on_top_toggle --- src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs b/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs index b6c8bcf8..651c1787 100644 --- a/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs +++ b/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs @@ -165,10 +165,14 @@ public async Task Progress_bar_and_always_on_top_toggle() { var win = this.fx.MainWindow; win.SetProgressBar(0.5); + await Task.Delay(50); win.SetProgressBar(0.8, new ProgressBarOptions { Mode = ProgressBarMode.normal }); + await Task.Delay(50); win.SetAlwaysOnTop(true); + await Task.Delay(500); (await win.IsAlwaysOnTopAsync()).Should().BeTrue(); win.SetAlwaysOnTop(false); + await Task.Delay(500); (await win.IsAlwaysOnTopAsync()).Should().BeFalse(); } From 2cf309545013d1f03b10aeac857373458b946e7d Mon Sep 17 00:00:00 2001 From: softworkz Date: Sun, 16 Nov 2025 03:05:33 +0100 Subject: [PATCH 3/3] BrowserWindowTests: Add delays everywhere --- .../Tests/BrowserWindowTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs b/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs index 651c1787..6c0bd7e2 100644 --- a/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs +++ b/src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs @@ -21,6 +21,7 @@ public async Task Can_set_and_get_title() { const string title = "Integration Test Title"; this.fx.MainWindow.SetTitle(title); + await Task.Delay(500); var roundTrip = await this.fx.MainWindow.GetTitleAsync(); roundTrip.Should().Be(title); } @@ -29,6 +30,7 @@ public async Task Can_set_and_get_title() public async Task Can_resize_and_get_size() { this.fx.MainWindow.SetSize(643, 482); + await Task.Delay(500); var size = await this.fx.MainWindow.GetSizeAsync(); size.Should().HaveCount(2); size[0].Should().Be(643); @@ -58,6 +60,7 @@ public async Task Can_set_and_get_bounds() { var bounds = new Rectangle { X = 10, Y = 20, Width = 400, Height = 300 }; this.fx.MainWindow.SetBounds(bounds); + await Task.Delay(500); var round = await this.fx.MainWindow.GetBoundsAsync(); round.Should().BeEquivalentTo(bounds); @@ -70,6 +73,7 @@ public async Task Can_set_and_get_content_bounds() { var bounds = new Rectangle { X = 0, Y = 0, Width = 300, Height = 200 }; this.fx.MainWindow.SetContentBounds(bounds); + await Task.Delay(500); var round = await this.fx.MainWindow.GetContentBoundsAsync(); round.Width.Should().BeGreaterThan(0); round.Height.Should().BeGreaterThan(0); @@ -79,8 +83,10 @@ public async Task Can_set_and_get_content_bounds() public async Task Show_hide_visibility_roundtrip() { this.fx.MainWindow.Show(); + await Task.Delay(500); (await this.fx.MainWindow.IsVisibleAsync()).Should().BeTrue(); this.fx.MainWindow.Hide(); + await Task.Delay(500); (await this.fx.MainWindow.IsVisibleAsync()).Should().BeFalse(); } @@ -88,8 +94,10 @@ public async Task Show_hide_visibility_roundtrip() public async Task AlwaysOnTop_toggle_and_query() { this.fx.MainWindow.SetAlwaysOnTop(true); + await Task.Delay(500); (await this.fx.MainWindow.IsAlwaysOnTopAsync()).Should().BeTrue(); this.fx.MainWindow.SetAlwaysOnTop(false); + await Task.Delay(500); (await this.fx.MainWindow.IsAlwaysOnTopAsync()).Should().BeFalse(); } @@ -119,6 +127,7 @@ public async Task ReadyToShow_event_fires_after_content_ready() // Trigger a navigation and wait for DOM ready so the renderer paints, which emits ready-to-show var domReadyTcs = new TaskCompletionSource(); window.WebContents.OnDomReady += () => domReadyTcs.TrySetResult(); + await Task.Delay(500); await window.WebContents.LoadURLAsync("about:blank"); await domReadyTcs.Task; @@ -139,6 +148,7 @@ public async Task PageTitleUpdated_event_fires_on_title_change() // Navigate and wait for DOM ready, then change the document.title to trigger the event var domReadyTcs = new TaskCompletionSource(); window.WebContents.OnDomReady += () => domReadyTcs.TrySetResult(); + await Task.Delay(500); await window.WebContents.LoadURLAsync("about:blank"); await domReadyTcs.Task; await window.WebContents.ExecuteJavaScriptAsync("document.title='NewTitle';"); @@ -155,6 +165,7 @@ public async Task Resize_event_fires_on_size_change() var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false }, "about:blank"); var resized = false; window.OnResize += () => resized = true; + await Task.Delay(500); window.SetSize(500, 400); await Task.Delay(300); resized.Should().BeTrue(); @@ -183,8 +194,10 @@ public async Task Menu_bar_visibility_and_auto_hide() { var win = this.fx.MainWindow; win.SetAutoHideMenuBar(true); + await Task.Delay(500); (await win.IsMenuBarAutoHideAsync()).Should().BeTrue(); win.SetMenuBarVisibility(true); + await Task.Delay(500); (await win.IsMenuBarVisibleAsync()).Should().BeTrue(); } @@ -194,6 +207,7 @@ public async Task Parent_child_relationship_roundtrip() var child = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false, Width = 300, Height = 200 }, "about:blank"); this.fx.MainWindow.SetParentWindow(null); // ensure top-level child.SetParentWindow(this.fx.MainWindow); + await Task.Delay(500); var parent = await child.GetParentWindowAsync(); parent.Id.Should().Be(this.fx.MainWindow.Id); var kids = await this.fx.MainWindow.GetChildWindowsAsync();