diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj
index a53f9314..1120cec3 100644
--- a/src/fe-gtk/fe-gtk.vcxproj
+++ b/src/fe-gtk/fe-gtk.vcxproj
@@ -31,7 +31,7 @@
$(ArchiveLibDir);$(DepsRoot)\lib;%(AdditionalLibraryDirectories)
- $(DepLibs);$(ZoiteChatLib)common.lib;wbemuuid.lib;dwmapi.lib;%(AdditionalDependencies)
+ $(DepLibs);$(ZoiteChatLib)common.lib;wbemuuid.lib;dwmapi.lib;ole32.lib;uuid.lib;%(AdditionalDependencies)
mainCRTStartup
diff --git a/src/fe-gtk/meson.build b/src/fe-gtk/meson.build
index 5de0653f..abb21627 100644
--- a/src/fe-gtk/meson.build
+++ b/src/fe-gtk/meson.build
@@ -92,6 +92,8 @@ if host_machine.system() == 'windows'
zoitechat_gtk_sources += 'notifications/notification-windows.c'
zoitechat_gtk_deps += cc.find_library('dwmapi', required: true)
zoitechat_gtk_deps += cc.find_library('shell32', required: true)
+ zoitechat_gtk_deps += cc.find_library('ole32', required: true)
+ zoitechat_gtk_deps += cc.find_library('uuid', required: true)
zoitechat_theme_deps += cc.find_library('dwmapi', required: true)
else
diff --git a/src/fe-gtk/plugin-tray.c b/src/fe-gtk/plugin-tray.c
index 29314707..7b9386f2 100644
--- a/src/fe-gtk/plugin-tray.c
+++ b/src/fe-gtk/plugin-tray.c
@@ -35,6 +35,7 @@
#ifdef WIN32
#include
#include
+#include
#include
#endif
#if defined(GTK_DISABLE_DEPRECATED)
@@ -131,6 +132,7 @@ static void tray_menu_notify_cb (GObject *tray, GParamSpec *pspec, gpointer user
static void tray_update_toggle_item_label (void);
static gboolean tray_window_state_cb (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata);
static void tray_window_visibility_cb (GtkWidget *widget, gpointer userdata);
+static WinStatus tray_get_window_status (void);
static void tray_toggle_item_destroy_cb (GtkWidget *widget, gpointer userdata);
#if HAVE_APPINDICATOR_BACKEND
static void tray_menu_show_cb (GtkWidget *menu, gpointer userdata) G_GNUC_UNUSED;
@@ -158,6 +160,8 @@ static GtkStatusIcon *tray_status_icon;
#ifdef WIN32
static HWND tray_win32_hwnd;
static HICON tray_win32_icon;
+static HICON tray_win32_overlay_icon;
+static ITaskbarList3 *tray_win32_taskbar;
static gboolean tray_win32_active;
static UINT tray_win32_taskbar_created;
static const UINT tray_win32_callback_msg = WM_APP + 42;
@@ -606,6 +610,132 @@ tray_win32_pixbuf_to_hicon (GdkPixbuf *pixbuf)
return icon;
}
+static HWND
+tray_win32_get_main_hwnd (void)
+{
+ GtkWindow *win;
+ GdkWindow *gdk_window;
+
+ win = GTK_WINDOW (zoitechat_get_info (ph, "gtkwin_ptr"));
+ if (!win)
+ return NULL;
+
+ gdk_window = gtk_widget_get_window (GTK_WIDGET (win));
+ if (!gdk_window)
+ return NULL;
+
+ return gdk_win32_window_get_handle (gdk_window);
+}
+
+static ITaskbarList3 *
+tray_win32_get_taskbar (void)
+{
+ HRESULT hr;
+
+ if (tray_win32_taskbar)
+ return tray_win32_taskbar;
+
+ hr = CoCreateInstance (&CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
+ &IID_ITaskbarList3, (void **)&tray_win32_taskbar);
+ if (FAILED (hr))
+ return NULL;
+
+ hr = tray_win32_taskbar->lpVtbl->HrInit (tray_win32_taskbar);
+ if (FAILED (hr))
+ {
+ tray_win32_taskbar->lpVtbl->Release (tray_win32_taskbar);
+ tray_win32_taskbar = NULL;
+ return NULL;
+ }
+
+ return tray_win32_taskbar;
+}
+
+static void
+tray_win32_release_attention (void)
+{
+ if (tray_win32_overlay_icon)
+ {
+ DestroyIcon (tray_win32_overlay_icon);
+ tray_win32_overlay_icon = NULL;
+ }
+
+ if (tray_win32_taskbar)
+ {
+ tray_win32_taskbar->lpVtbl->Release (tray_win32_taskbar);
+ tray_win32_taskbar = NULL;
+ }
+}
+
+static void
+tray_win32_clear_attention (void)
+{
+ FLASHWINFO flash;
+ ITaskbarList3 *taskbar;
+ HWND hwnd;
+
+ hwnd = tray_win32_get_main_hwnd ();
+ if (!hwnd)
+ return;
+
+ ZeroMemory (&flash, sizeof (flash));
+ flash.cbSize = sizeof (flash);
+ flash.hwnd = hwnd;
+ flash.dwFlags = FLASHW_STOP;
+ FlashWindowEx (&flash);
+
+ taskbar = tray_win32_get_taskbar ();
+ if (taskbar)
+ taskbar->lpVtbl->SetOverlayIcon (taskbar, hwnd, NULL, L"");
+
+ if (tray_win32_overlay_icon)
+ {
+ DestroyIcon (tray_win32_overlay_icon);
+ tray_win32_overlay_icon = NULL;
+ }
+}
+
+static void
+tray_win32_set_attention (TrayIcon icon)
+{
+ FLASHWINFO flash;
+ ITaskbarList3 *taskbar;
+ HICON hicon;
+ HWND hwnd;
+
+ if (tray_get_window_status () == WS_FOCUSED)
+ return;
+
+ hwnd = tray_win32_get_main_hwnd ();
+ if (!hwnd)
+ return;
+
+ ZeroMemory (&flash, sizeof (flash));
+ flash.cbSize = sizeof (flash);
+ flash.hwnd = hwnd;
+ flash.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
+ FlashWindowEx (&flash);
+
+ taskbar = tray_win32_get_taskbar ();
+ if (!taskbar)
+ return;
+
+ hicon = tray_win32_pixbuf_to_hicon (icon);
+ if (!hicon)
+ return;
+
+ if (SUCCEEDED (taskbar->lpVtbl->SetOverlayIcon (taskbar, hwnd, hicon, L"")))
+ {
+ if (tray_win32_overlay_icon)
+ DestroyIcon (tray_win32_overlay_icon);
+ tray_win32_overlay_icon = hicon;
+ }
+ else
+ {
+ DestroyIcon (hicon);
+ }
+}
+
static void
tray_win32_init_data (NOTIFYICONDATAW *nid)
{
@@ -710,6 +840,8 @@ tray_win32_cleanup (void)
tray_win32_icon = NULL;
}
+ tray_win32_release_attention ();
+
if (tray_win32_hwnd)
{
DestroyWindow (tray_win32_hwnd);
@@ -1025,6 +1157,10 @@ tray_stop_flash (void)
flash_tag = 0;
}
+#ifdef WIN32
+ tray_win32_clear_attention ();
+#endif
+
if (tray_backend_active)
{
tray_set_icon_state (ICON_NORMAL, TRAY_ICON_NORMAL);
@@ -1641,6 +1777,9 @@ tray_hilight_cb (char *word[], void *userdata)
if (prefs.hex_input_tray_hilight)
{
tray_set_flash (ICON_HILIGHT, TRAY_ICON_HIGHLIGHT);
+#ifdef WIN32
+ tray_win32_set_attention (ICON_HILIGHT);
+#endif
/* FIXME: hides any previous private messages */
tray_hilight_count++;
@@ -1692,6 +1831,9 @@ tray_priv (char *from, char *text)
if (prefs.hex_input_tray_priv)
{
tray_set_flash (ICON_MSG, TRAY_ICON_MESSAGE);
+#ifdef WIN32
+ tray_win32_set_attention (ICON_MSG);
+#endif
tray_priv_count++;
if (tray_priv_count == 1)
@@ -1763,6 +1905,9 @@ tray_cleanup (void)
if (tray_backend_active)
tray_backend_cleanup ();
+#ifdef WIN32
+ tray_win32_release_attention ();
+#endif
}
void