diff --git a/src/main/ipc.ts b/src/main/ipc.ts
index a17bc9c..e174bce 100644
--- a/src/main/ipc.ts
+++ b/src/main/ipc.ts
@@ -142,6 +142,11 @@ handle(IpcEvents.SELECT_VENCORD_DIR, async (_e, value?: null) => {
handle(IpcEvents.SET_BADGE_COUNT, (_, count: number) => setBadgeCount(count));
+handle(IpcEvents.FLASH_FRAME, (_, flag: boolean) => {
+ if (!mainWin || mainWin.isDestroyed() || (flag && mainWin.isFocused())) return;
+ mainWin.flashFrame(flag);
+});
+
handle(IpcEvents.CLIPBOARD_COPY_IMAGE, async (_, buf: ArrayBuffer, src: string) => {
clipboard.write({
html: `
`,
diff --git a/src/main/mainWindow.ts b/src/main/mainWindow.ts
index cb85a12..6b8b946 100644
--- a/src/main/mainWindow.ts
+++ b/src/main/mainWindow.ts
@@ -389,6 +389,10 @@ function createMainWindow() {
return false;
});
+ win.on("focus", () => {
+ win.flashFrame(false);
+ });
+
initWindowBoundsListeners(win);
if (!isDeckGameMode && (Settings.store.tray ?? true) && process.platform !== "darwin")
initTray(win, q => (isQuitting = q));
diff --git a/src/preload/VesktopNative.ts b/src/preload/VesktopNative.ts
index 51149c9..b15e65d 100644
--- a/src/preload/VesktopNative.ts
+++ b/src/preload/VesktopNative.ts
@@ -68,6 +68,7 @@ export const VesktopNative = {
close: (key?: string) => invoke(IpcEvents.CLOSE, key),
minimize: (key?: string) => invoke(IpcEvents.MINIMIZE, key),
maximize: (key?: string) => invoke(IpcEvents.MAXIMIZE, key),
+ flashFrame: (flag: boolean) => invoke(IpcEvents.FLASH_FRAME, flag),
setDevtoolsCallbacks: (onOpen: () => void, onClose: () => void) => {
onDevtoolsOpen = onOpen;
onDevtoolsClose = onClose;
diff --git a/src/renderer/components/settings/Settings.tsx b/src/renderer/components/settings/Settings.tsx
index d14c144..82a58db 100644
--- a/src/renderer/components/settings/Settings.tsx
+++ b/src/renderer/components/settings/Settings.tsx
@@ -124,7 +124,15 @@ const SettingsOptions: Record>
defaultValue: false
}
],
- Notifications: [NotificationBadgeToggle],
+ Notifications: [
+ NotificationBadgeToggle,
+ {
+ key: "enableTaskbarFlashing",
+ title: "Enable Taskbar Flashing",
+ description: "Flashes the app in your taskbar when you have new notifications.",
+ defaultValue: false
+ }
+ ],
Miscellaneous: [
{
key: "arRPC",
diff --git a/src/renderer/patches/taskBarFlash.ts b/src/renderer/patches/taskBarFlash.ts
new file mode 100644
index 0000000..fec647c
--- /dev/null
+++ b/src/renderer/patches/taskBarFlash.ts
@@ -0,0 +1,27 @@
+/*
+ * Vesktop, a desktop app aiming to give you a snappier Discord Experience
+ * Copyright (c) 2025 Vendicated and Vesktop contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { Settings } from "renderer/settings";
+
+import { addPatch } from "./shared";
+
+addPatch({
+ patches: [
+ {
+ find: ".flashFrame(!0)",
+ replacement: {
+ match: /(\i)&&\i\.\i\.taskbarFlash&&\i\.\i\.flashFrame\(!0\)/,
+ replace: "$self.flashFrame()"
+ }
+ }
+ ],
+
+ flashFrame() {
+ if (Settings.store.enableTaskbarFlashing) {
+ VesktopNative.win.flashFrame(true);
+ }
+ }
+});
diff --git a/src/shared/IpcEvents.ts b/src/shared/IpcEvents.ts
index 9052fbe..da69b02 100644
--- a/src/shared/IpcEvents.ts
+++ b/src/shared/IpcEvents.ts
@@ -36,6 +36,7 @@ export const enum IpcEvents {
SPELLCHECK_ADD_TO_DICTIONARY = "VCD_SPELLCHECK_ADD_TO_DICTIONARY",
SET_BADGE_COUNT = "VCD_SET_BADGE_COUNT",
+ FLASH_FRAME = "FLASH_FRAME",
CAPTURER_GET_LARGE_THUMBNAIL = "VCD_CAPTURER_GET_LARGE_THUMBNAIL",
diff --git a/src/shared/settings.d.ts b/src/shared/settings.d.ts
index 4b4a7e5..5b8fd6f 100644
--- a/src/shared/settings.d.ts
+++ b/src/shared/settings.d.ts
@@ -20,6 +20,7 @@ export interface Settings {
hardwareVideoAcceleration?: boolean;
arRPC?: boolean;
appBadge?: boolean;
+ enableTaskbarFlashing?: boolean;
disableMinSize?: boolean;
clickTrayToShowHide?: boolean;
customTitleBar?: boolean;