From 0d14da25d26d3ce24842ecf92ec49326d1141491 Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Sat, 22 Jul 2023 15:10:50 +0200 Subject: [PATCH 1/6] Started Windows Support for Balloon Messages --- tray.h | 2 ++ tray_linux.c | 3 +++ tray_windows.c | 23 ++++++++++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tray.h b/tray.h index 26d1426f..1b3c1113 100644 --- a/tray.h +++ b/tray.h @@ -11,6 +11,8 @@ struct tray_menu; struct tray { const char *icon; char *tooltip; + char *notification_text; + char *notification_title; struct tray_menu *menu; }; diff --git a/tray_linux.c b/tray_linux.c index 4f6b029b..aee1a48c 100644 --- a/tray_linux.c +++ b/tray_linux.c @@ -62,6 +62,9 @@ void tray_update(struct tray *tray) { // GTK is all about reference counting, so previous menu should be destroyed // here app_indicator_set_menu(indicator, GTK_MENU(_tray_menu(tray->menu))); + if(tray->notification_text != 0 && strlen(tray->notification_text) > 0){ + + } } void tray_exit(void) { loop_result = -1; } diff --git a/tray_windows.c b/tray_windows.c index c2d078da..74aa37ff 100644 --- a/tray_windows.c +++ b/tray_windows.c @@ -139,16 +139,37 @@ void tray_update(struct tray *tray) { UINT id = ID_TRAY_FIRST; hmenu = _tray_menu(tray->menu, &id); SendMessage(hwnd, WM_INITMENUPOPUP, (WPARAM)hmenu, 0); - HICON icon; + HICON icon,largeIcon; ExtractIconEx(tray->icon, 0, NULL, &icon, 1); + ExtractIconEx(tray->icon, 0, &largeIcon, NULL, 1); if (nid.hIcon) { DestroyIcon(nid.hIcon); } + if(nid.hBalloonIcon){ + DestroyIcon(nid.hBalloonIcon); + } nid.hIcon = icon; + if(largeIcon){ + nid.hBalloonIcon = largeIcon; + } if(tray->tooltip != 0 && strlen(tray->tooltip) > 0) { strncpy(nid.szTip, tray->tooltip, sizeof(nid.szTip)); nid.uFlags |= NIF_TIP; } + if(tray->notification_title != 0 && strlen(tray->notification_title) > 0){ + strncpy(nid.szInfoTitle, tray->notification_title, sizeof(nid.szInfoTitle)); + nid.uFlags = NIF_INFO; + if(largeIcon){ + nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; + } + } else if((nid.uFlags & NIF_INFO) == NIF_INFO) { + strncpy(nid.szInfoTitle, "", sizeof(nid.szInfoTitle)); + } + if(tray->notification_text != 0 && strlen(tray->notification_text) > 0){ + strncpy(nid.szInfo, tray->notification_text, sizeof(nid.szInfo)); + } else if((nid.uFlags & NIF_INFO) == NIF_INFO) { + strncpy(nid.szInfo, "", sizeof(nid.szInfo)); + } Shell_NotifyIcon(NIM_MODIFY, &nid); if (prevmenu != NULL) { From f8179dd9e091029bfce843f03f9be3d33ef5a95d Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Sun, 23 Jul 2023 12:22:25 +0000 Subject: [PATCH 2/6] Linux Notification support --- CMakeLists.txt | 6 +++-- cmake/FindLIBNOTIFY.cmake | 55 +++++++++++++++++++++++++++++++++++++++ tray_linux.c | 53 +++++++++++++++++++++++-------------- 3 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 cmake/FindLIBNOTIFY.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index abcf5ab0..9bccb8de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ else() list(APPEND SRCS ${CMAKE_CURRENT_SOURCE_DIR}/tray_darwin.m) else() find_package(APPINDICATOR REQUIRED) + find_package(LIBNOTIFY REQUIRED) list(APPEND SRCS ${CMAKE_CURRENT_SOURCE_DIR}/tray_linux.c) endif() endif() @@ -46,9 +47,10 @@ else() target_link_libraries(tray PRIVATE ${COCOA}) else() target_compile_options(tray PRIVATE ${APPINDICATOR_CFLAGS}) - target_link_directories(tray PRIVATE ${APPINDICATOR_LIBRARY_DIRS}) + target_link_directories(tray PRIVATE ${APPINDICATOR_LIBRARY_DIRS}}) target_compile_definitions(tray PRIVATE TRAY_APPINDICATOR=1) - target_link_libraries(tray PRIVATE ${APPINDICATOR_LIBRARIES}) + target_compile_definitions(tray PRIVATE TRAY_LIBNOTIFY=1) + target_link_libraries(tray PRIVATE ${APPINDICATOR_LIBRARIES} ${LIBNOTIFY_LIBRARIES}) endif() endif() endif() diff --git a/cmake/FindLIBNOTIFY.cmake b/cmake/FindLIBNOTIFY.cmake new file mode 100644 index 00000000..e76b199b --- /dev/null +++ b/cmake/FindLIBNOTIFY.cmake @@ -0,0 +1,55 @@ +# - Try to find LibNotify +# This module defines the following variables: +# +# LIBNOTIFY_FOUND - LibNotify was found +# LIBNOTIFY_INCLUDE_DIRS - the LibNotify include directories +# LIBNOTIFY_LIBRARIES - link these to use LibNotify +# +# Copyright (C) 2012 Raphael Kubo da Costa +# Copyright (C) 2014 Collabora Ltd. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_package(PkgConfig) +pkg_check_modules(LIBNOTIFY QUIET libnotify) + +find_path(LIBNOTIFY_INCLUDE_DIRS + NAMES notify.h + HINTS ${LIBNOTIFY_INCLUDEDIR} + ${LIBNOTIFY_INCLUDE_DIRS} + PATH_SUFFIXES libnotify +) + +find_library(LIBNOTIFY_LIBRARIES + NAMES notify + HINTS ${LIBNOTIFY_LIBDIR} + ${LIBNOTIFY_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibNotify REQUIRED_VARS LIBNOTIFY_INCLUDE_DIRS LIBNOTIFY_LIBRARIES + VERSION_VAR LIBNOTIFY_VERSION) + +mark_as_advanced( + LIBNOTIFY_INCLUDE_DIRS + LIBNOTIFY_LIBRARIES +) diff --git a/tray_linux.c b/tray_linux.c index 21db4f40..b09836e0 100644 --- a/tray_linux.c +++ b/tray_linux.c @@ -1,13 +1,13 @@ #include "tray.h" -#include -#include #include - +#include +#include +#include #define TRAY_APPINDICATOR_ID "tray-id" static AppIndicator *indicator = NULL; -static int loop_result = 0; - +static int loop_result = 0; +static NotifyNotification *currentNotification = NULL; static void _tray_menu_cb(GtkMenuItem *item, gpointer data) { (void)item; struct tray_menu *m = (struct tray_menu *)data; @@ -16,23 +16,26 @@ static void _tray_menu_cb(GtkMenuItem *item, gpointer data) { static GtkMenuShell *_tray_menu(struct tray_menu *m) { GtkMenuShell *menu = (GtkMenuShell *)gtk_menu_new(); - for (; m != NULL && m->text != NULL; m++) { + for(; m != NULL && m->text != NULL; m++) { GtkWidget *item; - if (strcmp(m->text, "-") == 0) { + if(strcmp(m->text, "-") == 0) { item = gtk_separator_menu_item_new(); - } else { - if (m->submenu != NULL) { + } + else { + if(m->submenu != NULL) { item = gtk_menu_item_new_with_label(m->text); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), - GTK_WIDGET(_tray_menu(m->submenu))); - } else if (m->checkbox) { + GTK_WIDGET(_tray_menu(m->submenu))); + } + else if(m->checkbox) { item = gtk_check_menu_item_new_with_label(m->text); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), !!m->checked); - } else { + } + else { item = gtk_menu_item_new_with_label(m->text); } gtk_widget_set_sensitive(item, !m->disabled); - if (m->cb != NULL) { + if(m->cb != NULL) { g_signal_connect(item, "activate", G_CALLBACK(_tray_menu_cb), m); } } @@ -43,12 +46,13 @@ static GtkMenuShell *_tray_menu(struct tray_menu *m) { } int tray_init(struct tray *tray) { - if (gtk_init_check(0, NULL) == FALSE) { + if(gtk_init_check(0, NULL) == FALSE) { return -1; } indicator = app_indicator_new(TRAY_APPINDICATOR_ID, tray->icon, - APP_INDICATOR_CATEGORY_APPLICATION_STATUS); + APP_INDICATOR_CATEGORY_APPLICATION_STATUS); app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE); + notify_init("tray-icon"); tray_update(tray); return 0; } @@ -63,10 +67,21 @@ void tray_update(struct tray *tray) { // GTK is all about reference counting, so previous menu should be destroyed // here app_indicator_set_menu(indicator, GTK_MENU(_tray_menu(tray->menu))); - if(tray->notification_text != 0 && strlen(tray->notification_text) > 0){ - + if(tray->notification_text != 0 && strlen(tray->notification_text) > 0 && notify_is_initted()) { + if(currentNotification != NULL){ + notify_notification_close(currentNotification,NULL); + g_object_unref(G_OBJECT(currentNotification)); + } + currentNotification = notify_notification_new(tray->notification_title, tray->notification_text, tray->icon); + notify_notification_show(currentNotification, NULL); } } -void tray_exit(void) { loop_result = -1; } - +void tray_exit(void) { + if(currentNotification != NULL){ + int v = notify_notification_close(currentNotification,NULL); + if(v == TRUE)g_object_unref(G_OBJECT(currentNotification)); + } + notify_uninit(); + loop_result = -1; +} From d6f00f4fbe859d5f58a68a9af41d540dd84e7323 Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Sun, 23 Jul 2023 19:32:40 +0200 Subject: [PATCH 3/6] Balloon Callback --- tray.h | 6 ++++-- tray_linux.c | 3 ++- tray_windows.c | 9 ++++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tray.h b/tray.h index 1b3c1113..86410505 100644 --- a/tray.h +++ b/tray.h @@ -11,8 +11,10 @@ struct tray_menu; struct tray { const char *icon; char *tooltip; - char *notification_text; - char *notification_title; + const char *notification_text; + const char *notification_title; + const char *notification_icon; + void (*notification_cb)(); struct tray_menu *menu; }; diff --git a/tray_linux.c b/tray_linux.c index b09836e0..6d169d2c 100644 --- a/tray_linux.c +++ b/tray_linux.c @@ -72,7 +72,8 @@ void tray_update(struct tray *tray) { notify_notification_close(currentNotification,NULL); g_object_unref(G_OBJECT(currentNotification)); } - currentNotification = notify_notification_new(tray->notification_title, tray->notification_text, tray->icon); + const char *notification_icon = tray->notification_icon != NULL ? tray->notification_icon : tray->icon; + currentNotification = notify_notification_new(tray->notification_title, tray->notification_text, notification_icon); notify_notification_show(currentNotification, NULL); } } diff --git a/tray_windows.c b/tray_windows.c index 74aa37ff..bd4c9347 100644 --- a/tray_windows.c +++ b/tray_windows.c @@ -10,6 +10,7 @@ static WNDCLASSEX wc; static NOTIFYICONDATA nid; static HWND hwnd; static HMENU hmenu = NULL; +static void (*notification_cb)() = 0; static UINT wm_taskbarcreated; static LRESULT CALLBACK _tray_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, @@ -31,6 +32,8 @@ static LRESULT CALLBACK _tray_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, p.x, p.y, 0, hwnd, NULL); SendMessage(hwnd, WM_COMMAND, cmd, 0); return 0; + } else if(lparam == NIN_BALLOONUSERCLICK && notification_cb != NULL){ + notification_cb(); } break; case WM_COMMAND: @@ -139,9 +142,10 @@ void tray_update(struct tray *tray) { UINT id = ID_TRAY_FIRST; hmenu = _tray_menu(tray->menu, &id); SendMessage(hwnd, WM_INITMENUPOPUP, (WPARAM)hmenu, 0); + const char *notification_icon = tray->notification_icon != NULL ? tray->notification_icon : tray->icon; HICON icon,largeIcon; ExtractIconEx(tray->icon, 0, NULL, &icon, 1); - ExtractIconEx(tray->icon, 0, &largeIcon, NULL, 1); + ExtractIconEx(notification_icon, 0, &largeIcon, NULL, 1); if (nid.hIcon) { DestroyIcon(nid.hIcon); } @@ -170,6 +174,9 @@ void tray_update(struct tray *tray) { } else if((nid.uFlags & NIF_INFO) == NIF_INFO) { strncpy(nid.szInfo, "", sizeof(nid.szInfo)); } + if(tray->notification_cb != NULL){ + notification_cb = tray->notification_cb; + } Shell_NotifyIcon(NIM_MODIFY, &nid); if (prevmenu != NULL) { From 6c8600a902e0590df1651d079f6736d7d3102ac6 Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Sun, 13 Aug 2023 23:14:45 +0200 Subject: [PATCH 4/6] Windows fixes --- tray.h | 2 +- tray_windows.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/tray.h b/tray.h index 86410505..e735ecb1 100644 --- a/tray.h +++ b/tray.h @@ -11,9 +11,9 @@ struct tray_menu; struct tray { const char *icon; char *tooltip; + const char *notification_icon; const char *notification_text; const char *notification_title; - const char *notification_icon; void (*notification_cb)(); struct tray_menu *menu; }; diff --git a/tray_windows.c b/tray_windows.c index bd4c9347..1914afc6 100644 --- a/tray_windows.c +++ b/tray_windows.c @@ -142,10 +142,13 @@ void tray_update(struct tray *tray) { UINT id = ID_TRAY_FIRST; hmenu = _tray_menu(tray->menu, &id); SendMessage(hwnd, WM_INITMENUPOPUP, (WPARAM)hmenu, 0); - const char *notification_icon = tray->notification_icon != NULL ? tray->notification_icon : tray->icon; HICON icon,largeIcon; ExtractIconEx(tray->icon, 0, NULL, &icon, 1); - ExtractIconEx(notification_icon, 0, &largeIcon, NULL, 1); + if(tray->notification_icon != 0){ + ExtractIconEx(tray->notification_icon, 0, &largeIcon, NULL, 1); + } else { + ExtractIconEx(tray->icon, 0, &largeIcon, NULL, 1); + } if (nid.hIcon) { DestroyIcon(nid.hIcon); } @@ -153,8 +156,9 @@ void tray_update(struct tray *tray) { DestroyIcon(nid.hBalloonIcon); } nid.hIcon = icon; - if(largeIcon){ + if(largeIcon != 0){ nid.hBalloonIcon = largeIcon; + nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; } if(tray->tooltip != 0 && strlen(tray->tooltip) > 0) { strncpy(nid.szTip, tray->tooltip, sizeof(nid.szTip)); @@ -163,15 +167,14 @@ void tray_update(struct tray *tray) { if(tray->notification_title != 0 && strlen(tray->notification_title) > 0){ strncpy(nid.szInfoTitle, tray->notification_title, sizeof(nid.szInfoTitle)); nid.uFlags = NIF_INFO; - if(largeIcon){ - nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; - } } else if((nid.uFlags & NIF_INFO) == NIF_INFO) { + nid.uFlags ^= ~NIF_INFO; strncpy(nid.szInfoTitle, "", sizeof(nid.szInfoTitle)); } if(tray->notification_text != 0 && strlen(tray->notification_text) > 0){ strncpy(nid.szInfo, tray->notification_text, sizeof(nid.szInfo)); } else if((nid.uFlags & NIF_INFO) == NIF_INFO) { + nid.uFlags ^= ~NIF_INFO; strncpy(nid.szInfo, "", sizeof(nid.szInfo)); } if(tray->notification_cb != NULL){ From 53db1338ae3859afb439051031955f90bdec31fe Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Sun, 13 Aug 2023 23:14:51 +0200 Subject: [PATCH 5/6] Balloon Callback on Linux --- tray_linux.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tray_linux.c b/tray_linux.c index 6d169d2c..6a7da881 100644 --- a/tray_linux.c +++ b/tray_linux.c @@ -74,6 +74,9 @@ void tray_update(struct tray *tray) { } const char *notification_icon = tray->notification_icon != NULL ? tray->notification_icon : tray->icon; currentNotification = notify_notification_new(tray->notification_title, tray->notification_text, notification_icon); + if(tray->notification_cb != NULL){ + notify_notification_add_action(currentNotification,"default","Default",tray->notification_cb,NULL,NULL); + } notify_notification_show(currentNotification, NULL); } } From 2594de996e1c703b30f0616a437e79389a35ac79 Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Sat, 19 Aug 2023 10:02:14 +0200 Subject: [PATCH 6/6] Update CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bccb8de..6a1e5001 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ else() target_link_libraries(tray PRIVATE ${COCOA}) else() target_compile_options(tray PRIVATE ${APPINDICATOR_CFLAGS}) - target_link_directories(tray PRIVATE ${APPINDICATOR_LIBRARY_DIRS}}) + target_link_directories(tray PRIVATE ${APPINDICATOR_LIBRARY_DIRS}) target_compile_definitions(tray PRIVATE TRAY_APPINDICATOR=1) target_compile_definitions(tray PRIVATE TRAY_LIBNOTIFY=1) target_link_libraries(tray PRIVATE ${APPINDICATOR_LIBRARIES} ${LIBNOTIFY_LIBRARIES})