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