From f4f27e438b0791e1c0708c4f031aa80c59d965b1 Mon Sep 17 00:00:00 2001 From: TingPing Date: Mon, 2 Feb 2015 19:35:49 -0500 Subject: Implement windows 8.1+ notifications This splits notifications up into multiple backends currently only libnotify on unix and win8 toasts. The win8 backend was originally written by @leeter though heavily modified. --- src/common/fe.h | 1 - src/common/outbound.c | 6 - src/common/plugin.c | 20 +- src/common/plugin.h | 1 + src/fe-gtk/Makefile.am | 12 +- src/fe-gtk/fe-gtk.c | 3 + src/fe-gtk/fe-gtk.vcxproj | 9 +- src/fe-gtk/fe-gtk.vcxproj.filters | 11 +- src/fe-gtk/hexchat.exe.manifest | 22 -- src/fe-gtk/notifications/notification-backend.h | 27 +++ src/fe-gtk/notifications/notification-dummy.c | 39 ++++ src/fe-gtk/notifications/notification-libnotify.c | 73 +++++++ src/fe-gtk/notifications/notification-windows.c | 87 ++++++++ src/fe-gtk/notifications/notification-winrt.cpp | 100 +++++++++ .../notifications/notifications-winrt.vcxproj | 127 ++++++++++++ .../notifications-winrt.vcxproj.filters | 22 ++ src/fe-gtk/plugin-notification.c | 225 +++++++++++++++++++++ src/fe-gtk/plugin-notification.h | 25 +++ src/fe-gtk/plugin-tray.c | 107 ---------- src/fe-gtk/setup.c | 84 +++++++- src/fe-text/fe-text.c | 1 - 21 files changed, 841 insertions(+), 161 deletions(-) delete mode 100644 src/fe-gtk/hexchat.exe.manifest create mode 100644 src/fe-gtk/notifications/notification-backend.h create mode 100644 src/fe-gtk/notifications/notification-dummy.c create mode 100644 src/fe-gtk/notifications/notification-libnotify.c create mode 100644 src/fe-gtk/notifications/notification-windows.c create mode 100644 src/fe-gtk/notifications/notification-winrt.cpp create mode 100644 src/fe-gtk/notifications/notifications-winrt.vcxproj create mode 100644 src/fe-gtk/notifications/notifications-winrt.vcxproj.filters create mode 100644 src/fe-gtk/plugin-notification.c create mode 100644 src/fe-gtk/plugin-notification.h (limited to 'src') diff --git a/src/common/fe.h b/src/common/fe.h index 9d8919ac..a3bd2afa 100644 --- a/src/common/fe.h +++ b/src/common/fe.h @@ -178,7 +178,6 @@ typedef enum } feicon; void fe_tray_set_icon (feicon icon); void fe_tray_set_tooltip (const char *text); -void fe_tray_set_balloon (const char *title, const char *text); void fe_open_chan_list (server *serv, char *filter, int do_refresh); const char *fe_get_default_font (); diff --git a/src/common/outbound.c b/src/common/outbound.c index 8884b41e..ed00aa19 100644 --- a/src/common/outbound.c +++ b/src/common/outbound.c @@ -3470,12 +3470,6 @@ cmd_topic (struct session *sess, char *tbuf, char *word[], char *word_eol[]) static int cmd_tray (struct session *sess, char *tbuf, char *word[], char *word_eol[]) { - if (strcmp (word[2], "-b") == 0) - { - fe_tray_set_balloon (word[3], word[4][0] ? word[4] : NULL); - return TRUE; - } - if (strcmp (word[2], "-t") == 0) { fe_tray_set_tooltip (word[3][0] ? word[3] : NULL); diff --git a/src/common/plugin.c b/src/common/plugin.c index d2782e01..8d990dc9 100644 --- a/src/common/plugin.c +++ b/src/common/plugin.c @@ -355,15 +355,11 @@ plugin_kill_all (void) #ifdef USE_PLUGIN -/* load a plugin from a filename. Returns: NULL-success or an error string */ - -char * -plugin_load (session *sess, char *filename, char *arg) +GModule * +module_load (char *filename) { void *handle; char *filepart; - hexchat_init_func *init_func; - hexchat_deinit_func *deinit_func; char *pluginpath; /* get the filename without path */ @@ -383,6 +379,18 @@ plugin_load (session *sess, char *filename, char *arg) handle = g_module_open (filename, 0); } + return handle; +} + +/* load a plugin from a filename. Returns: NULL-success or an error string */ + +char * +plugin_load (session *sess, char *filename, char *arg) +{ + GModule *handle = module_load (filename); + hexchat_init_func *init_func; + hexchat_deinit_func *deinit_func; + if (handle == NULL) return (char *)g_module_error (); diff --git a/src/common/plugin.h b/src/common/plugin.h index db0054cb..5743f39a 100644 --- a/src/common/plugin.h +++ b/src/common/plugin.h @@ -163,6 +163,7 @@ struct _hexchat_plugin }; #endif +GModule *module_load (char *filename); char *plugin_load (session *sess, char *filename, char *arg); int plugin_reload (session *sess, char *name, int by_filename); void plugin_add (session *sess, char *filename, void *handle, void *init_func, void *deinit_func, char *arg, int fake); diff --git a/src/fe-gtk/Makefile.am b/src/fe-gtk/Makefile.am index 78ca1e45..28c932b1 100644 --- a/src/fe-gtk/Makefile.am +++ b/src/fe-gtk/Makefile.am @@ -12,7 +12,7 @@ hexchat_LDADD = ../common/libhexchatcommon.a $(GUI_LIBS) EXTRA_DIST = \ ascii.h banlist.h chanlist.h chanview.h chanview-tabs.c \ chanview-tree.c custom-list.h editlist.h fe-gtk.h fkeys.h gtkutil.h joind.h \ - maingui.h menu.h notifygui.h palette.h pixmaps.h \ + maingui.h menu.h notifygui.h notifications palette.h pixmaps.h plugin-notification.h \ plugin-tray.h plugingui.c plugingui.h rawlog.h sexy-iso-codes.h \ sexy-spell-entry.h textgui.h urlgrab.h userlistgui.h xtext.h \ ../../data/hexchat.gresource.xml @@ -29,10 +29,16 @@ if HAVE_ISO_CODES iso_codes_c = sexy-iso-codes.c endif +if USE_LIBNOTIFY +notify_c = notifications/notification-libnotify.c +else +notify_c = notifications/notification-dummy.c +endif + hexchat_SOURCES = ascii.c banlist.c chanlist.c chanview.c custom-list.c \ dccgui.c editlist.c fe-gtk.c fkeys.c gtkutil.c ignoregui.c joind.c menu.c \ - maingui.c notifygui.c palette.c pixmaps.c plugin-tray.c $(plugingui_c) \ - rawlog.c resources.c servlistgui.c setup.c $(iso_codes_c) \ + maingui.c notifygui.c $(notify_c) palette.c pixmaps.c plugin-tray.c $(plugingui_c) \ + plugin-notification.c rawlog.c resources.c servlistgui.c setup.c $(iso_codes_c) \ sexy-spell-entry.c textgui.c urlgrab.c userlistgui.c xtext.c hexchat_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/src/common diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index 21aa9b9b..8c163eb7 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -52,6 +52,7 @@ #include "plugin-tray.h" #include "urlgrab.h" #include "setup.h" +#include "plugin-notification.h" #ifdef USE_LIBCANBERRA #include @@ -381,6 +382,8 @@ fe_idle (gpointer data) { session *sess = sess_list->data; + plugin_add (sess, NULL, NULL, notification_plugin_init, notification_plugin_deinit, NULL, FALSE); + plugin_add (sess, NULL, NULL, tray_plugin_init, tray_plugin_deinit, NULL, FALSE); if (arg_minimize == 1) diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj index 59ab17c6..62790283 100644 --- a/src/fe-gtk/fe-gtk.vcxproj +++ b/src/fe-gtk/fe-gtk.vcxproj @@ -60,7 +60,7 @@ true true WIN32;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions) - $(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) + $(SolutionDir)..;..\common;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) true 4244;%(DisableSpecificWarnings) @@ -81,7 +81,7 @@ true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions) - $(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) + $(SolutionDir)..;..\common;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) true 4244;4267;%(DisableSpecificWarnings) @@ -120,6 +120,7 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u + @@ -150,9 +151,11 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u + + @@ -167,7 +170,7 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u - + diff --git a/src/fe-gtk/fe-gtk.vcxproj.filters b/src/fe-gtk/fe-gtk.vcxproj.filters index 4598b1f2..a950d02f 100644 --- a/src/fe-gtk/fe-gtk.vcxproj.filters +++ b/src/fe-gtk/fe-gtk.vcxproj.filters @@ -93,6 +93,9 @@ Header Files + + Header Files + @@ -182,9 +185,15 @@ Source Files + + Source Files + + + Source Files + - + Resource Files diff --git a/src/fe-gtk/hexchat.exe.manifest b/src/fe-gtk/hexchat.exe.manifest deleted file mode 100644 index 39c4eb4c..00000000 --- a/src/fe-gtk/hexchat.exe.manifest +++ /dev/null @@ -1,22 +0,0 @@ - - - - HexChat IRC Client - - - - - - diff --git a/src/fe-gtk/notifications/notification-backend.h b/src/fe-gtk/notifications/notification-backend.h new file mode 100644 index 00000000..98686d73 --- /dev/null +++ b/src/fe-gtk/notifications/notification-backend.h @@ -0,0 +1,27 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef HEXCHAT_PLUGIN_NOTIFICATION_BACKEND_H +#define HEXCHAT_PLUGIN_NOTIFICATION_BACKEND_H + +int notification_backend_supported (void); +void notification_backend_show (const char *title, const char *text, int timeout); +int notification_backend_init (void); +void notification_backend_deinit (void); + +#endif diff --git a/src/fe-gtk/notifications/notification-dummy.c b/src/fe-gtk/notifications/notification-dummy.c new file mode 100644 index 00000000..1b719cfa --- /dev/null +++ b/src/fe-gtk/notifications/notification-dummy.c @@ -0,0 +1,39 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +void +notification_backend_show (const char *title, const char *text, int timeout) +{ +} + +int +notification_backend_init (void) +{ + return 0; +} + +void +notification_backend_deinit (void) +{ +} + +int +notification_backend_supported (void) +{ + return 0; +} diff --git a/src/fe-gtk/notifications/notification-libnotify.c b/src/fe-gtk/notifications/notification-libnotify.c new file mode 100644 index 00000000..d3e3a992 --- /dev/null +++ b/src/fe-gtk/notifications/notification-libnotify.c @@ -0,0 +1,73 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#include + +static gboolean strip_markup = FALSE; + +void +notification_backend_show (const char *title, const char *text, int timeout) +{ + NotifyNotification *notification; + + if (strip_markup) + text = g_markup_escape_text (text, -1); + + notification = notify_notification_new (title, text, "hexchat"); + notify_notification_set_hint (notification, "desktop-entry", g_variant_new_string ("hexchat")); + + notify_notification_set_timeout (notification, timeout); + notify_notification_show (notification, NULL); + + g_object_unref (notification); + if (strip_markup) + g_free ((char*)text); +} + +int +notification_backend_init (void) +{ + GList* server_caps; + + if (!NOTIFY_CHECK_VERSION (0, 7, 0)) + return 0; + + if (!notify_init (PACKAGE_NAME)) + return 0; + + server_caps = notify_get_server_caps (); + if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)g_strcmp0)) + strip_markup = TRUE; + g_list_free_full (server_caps, g_free); + + return 1; +} + +void +notification_backend_deinit (void) +{ + notify_uninit (); +} + +int +notification_backend_supported (void) +{ + return notify_is_initted (); +} diff --git a/src/fe-gtk/notifications/notification-windows.c b/src/fe-gtk/notifications/notification-windows.c new file mode 100644 index 00000000..16cf3412 --- /dev/null +++ b/src/fe-gtk/notifications/notification-windows.c @@ -0,0 +1,87 @@ +/* HexChat + * Copyright (C) 2015 Arnav Singh. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "hexchat.h" +#include "plugin.h" + +#include + +void (*winrt_notification_backend_show) (const char *title, const char *text, int timeout) = NULL; +int (*winrt_notification_backend_init) (void) = NULL; +void (*winrt_notification_backend_deinit) (void) = NULL; +int (*winrt_notification_backend_supported) (void) = NULL; + +void +notification_backend_show (const char *title, const char *text, int timeout) +{ + if (winrt_notification_backend_show == NULL) + { + return; + } + + winrt_notification_backend_show (title, text, timeout); +} + +int +notification_backend_init (void) +{ + UINT original_error_mode; + GModule *module; + + /* Temporarily suppress the "DLL could not be loaded" dialog box before trying to load hcnotifications-winrt.dll */ + original_error_mode = GetErrorMode (); + SetErrorMode(SEM_FAILCRITICALERRORS); + module = module_load (HEXCHATLIBDIR "\\hcnotifications-winrt.dll"); + SetErrorMode (original_error_mode); + + if (module == NULL) + { + return 0; + } + + g_module_symbol (module, "notification_backend_show", (gpointer *) &winrt_notification_backend_show); + g_module_symbol (module, "notification_backend_init", (gpointer *) &winrt_notification_backend_init); + g_module_symbol (module, "notification_backend_deinit", (gpointer *) &winrt_notification_backend_deinit); + g_module_symbol (module, "notification_backend_supported", (gpointer *) &winrt_notification_backend_supported); + + return winrt_notification_backend_init (); +} + +void +notification_backend_deinit (void) +{ + if (winrt_notification_backend_deinit == NULL) + { + return; + } + + winrt_notification_backend_deinit (); +} + +int +notification_backend_supported (void) +{ + if (winrt_notification_backend_supported == NULL) + { + return 0; + } + + return winrt_notification_backend_supported (); +} diff --git a/src/fe-gtk/notifications/notification-winrt.cpp b/src/fe-gtk/notifications/notification-winrt.cpp new file mode 100644 index 00000000..74cc2e78 --- /dev/null +++ b/src/fe-gtk/notifications/notification-winrt.cpp @@ -0,0 +1,100 @@ +/* HexChat + * Copyright (c) 2014 Leetsoftwerx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include + +using namespace Windows::UI::Notifications; +using namespace Windows::Data::Xml::Dom; + +static ToastNotifier ^ notifier = nullptr; + +static std::wstring +widen(const std::string & to_widen) +{ + std::wstring_convert > converter; + return converter.from_bytes(to_widen); +} + +extern "C" +{ + __declspec (dllexport) void + notification_backend_show (const char *title, const char *text, int timeout) + { + try + { + auto toastTemplate = ToastNotificationManager::GetTemplateContent (ToastTemplateType::ToastText02); + auto node_list = toastTemplate->GetElementsByTagName ("text"); + UINT node_count = node_list->Length; + + auto wtitle = widen (title); + node_list->GetAt (0)->AppendChild ( + toastTemplate->CreateTextNode (Platform::StringReference (wtitle.c_str (), wtitle.size ()))); + + auto wtext = widen (text); + node_list->GetAt (1)->AppendChild ( + toastTemplate->CreateTextNode (Platform::StringReference (wtext.c_str (), wtext.size ()))); + + // Mute sound, we already play our own + auto node = toastTemplate->SelectSingleNode ("/toast"); + auto audio_elem = toastTemplate->CreateElement ("audio"); + audio_elem->SetAttribute ("silent", "true"); + static_cast(node)->AppendChild (audio_elem); + + notifier->Show (ref new ToastNotification (toastTemplate)); + } + catch (Platform::Exception ^ ex) + { + } + catch (...) + { + } + } + + __declspec (dllexport) int + notification_backend_init (void) + { + if (!notifier) + notifier = ToastNotificationManager::CreateToastNotifier ("HexChat.Desktop.Notify"); + + if (FAILED (Windows::Foundation::Initialize (RO_INIT_SINGLETHREADED))) + return 0; + + return 1; + } + + __declspec (dllexport) void + notification_backend_deinit (void) + { + notifier = nullptr; + Windows::Foundation::Uninitialize (); + } + + __declspec (dllexport) int + notification_backend_supported (void) + { + return 1; + } +} diff --git a/src/fe-gtk/notifications/notifications-winrt.vcxproj b/src/fe-gtk/notifications/notifications-winrt.vcxproj new file mode 100644 index 00000000..7a4e9888 --- /dev/null +++ b/src/fe-gtk/notifications/notifications-winrt.vcxproj @@ -0,0 +1,127 @@ + + + + + Release + Win32 + + + Release + x64 + + + + + true + true + + + + {C53145CC-D021-40C9-B97C-0249AB9A43C9} + Win32Proj + notifications-winrt + notifications-winrt + + + + DynamicLibrary + false + v120 + true + Unicode + + + DynamicLibrary + false + true + Unicode + v120 + + + + + + + + + + + + + + + false + hcnotifications-winrt + $(HexChatBin) + $(HexChatObj)$(ProjectName)\ + $(IncludePath) + $(LibraryPath) + + + false + $(HexChatBin) + hcnotifications-winrt + $(HexChatObj)$(ProjectName)\ + $(IncludePath) + $(LibraryPath) + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;NDEBUG;_WINDOWS;_USRDLL;NOTIFICATIONS_EXPORTS;%(PreprocessorDefinitions) + true + true + + $(VCInstallDir)vcpackages;$(FrameworkSdkDir)References\CommonConfiguration\Neutral;%(AdditionalUsingDirectories) + true + + + Windows + true + true + true + true + false + + + $(DepLibs);mincore.lib;runtimeobject.lib;%(AdditionalDependencies) + 6.03 + $(DepsRoot)\lib;%(AdditionalLibraryDirectories) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;NDEBUG;_WINDOWS;_USRDLL;NOTIFICATIONS_EXPORTS;%(PreprocessorDefinitions) + true + true + + $(VCInstallDir)vcpackages;$(FrameworkSdkDir)References\CommonConfiguration\Neutral;%(AdditionalUsingDirectories) + true + + + Windows + true + true + true + true + false + + + $(DepLibs);mincore.lib;runtimeobject.lib;%(AdditionalDependencies) + 6.03 + $(DepsRoot)\lib;%(AdditionalLibraryDirectories) + + + + + + \ No newline at end of file diff --git a/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters b/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters new file mode 100644 index 00000000..06f4e558 --- /dev/null +++ b/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/src/fe-gtk/plugin-notification.c b/src/fe-gtk/plugin-notification.c new file mode 100644 index 00000000..43ceeece --- /dev/null +++ b/src/fe-gtk/plugin-notification.c @@ -0,0 +1,225 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include + +#include "../common/hexchat-plugin.h" +#include "../common/inbound.h" /* For alert_match_word() */ +#include "notifications/notification-backend.h" + +static hexchat_plugin *ph; + +static gboolean +should_alert (void) +{ + int omit_away, omit_focused, omit_tray; + + if (hexchat_get_prefs (ph, "gui_focus_omitalerts", NULL, &omit_focused) == 3 && omit_focused) + { + const char *status = hexchat_get_info (ph, "win_status"); + + if (status && !g_strcmp0 (status, "active")) + return FALSE; + } + + if (hexchat_get_prefs (ph, "away_omit_alerts", NULL, &omit_away) == 3 && omit_away) + { + if (hexchat_get_info (ph, "away")) + return FALSE; + } + + if (hexchat_get_prefs (ph, "gui_tray_quiet", NULL, &omit_tray) == 3 && omit_tray) + { + int tray_enabled; + + if (hexchat_get_prefs (ph, "gui_tray", NULL, &tray_enabled) == 3 && tray_enabled) + { + const char *status = hexchat_get_info (ph, "win_status"); + + if (status && g_strcmp0 (status, "hidden") != 0) + return FALSE; + } + } + + return TRUE; +} + +/* Returns timeout in ms */ +static int +get_timeout (void) +{ + int timeout = 0; + hexchat_get_prefs (ph, "input_balloon_time", NULL, &timeout); + + return timeout * 1000; +} + +static gboolean +is_ignored (char *nick) +{ + const char *no_hilight; + + if (hexchat_get_prefs (ph, "irc_no_hilight", &no_hilight, NULL) == 1 && no_hilight) + { + return alert_match_word (nick, (char*)no_hilight); + } + return FALSE; +} + +static void +show_notification (const char *title, const char *text) +{ + char *stripped_title, *stripped_text; + + /* Strip all colors */ + stripped_title = hexchat_strip (ph, title, -1, 7); + stripped_text = hexchat_strip (ph, text, -1, 7); + + notification_backend_show (stripped_title, stripped_text, get_timeout ()); + + hexchat_free (ph, stripped_title); + hexchat_free (ph, stripped_text); +} + +static void +show_notificationf (const char *text, const char *format, ...) +{ + va_list args; + char *buf; + + va_start (args, format); + buf = g_strdup_vprintf (format, args); + va_end (args); + + show_notification (buf, text); + g_free (buf); +} + +static int +incoming_hilight_cb (char *word[], gpointer userdata) +{ + int hilight; + + if (hexchat_get_prefs (ph, "input_balloon_hilight", NULL, &hilight) == 3 && hilight && should_alert()) + { + show_notificationf (word[2], _("Highlighted message from: %s (%s)"), word[1], hexchat_get_info (ph, "channel")); + } + return HEXCHAT_EAT_NONE; +} + +static int +incoming_message_cb (char *word[], gpointer userdata) +{ + int message; + + if (hexchat_get_prefs (ph, "input_balloon_chans", NULL, &message) == 3 && message && should_alert ()) + { + show_notificationf (word[2], _("Channel message from: %s (%s)"), word[1], hexchat_get_info (ph, "channel")); + } + return HEXCHAT_EAT_NONE; +} + +static int +incoming_priv_cb (char *word[], gpointer userdata) +{ + int priv; + + if (hexchat_get_prefs (ph, "input_balloon_priv", NULL, &priv) == 3 && priv && should_alert ()) + { + const char *network = hexchat_get_info (ph, "network"); + if (!network) + network = hexchat_get_info (ph, "server"); + + if (userdata != NULL) /* Special event */ + { + if (GPOINTER_TO_INT (userdata) == 3) + { + if (!is_ignored (word[2])) + show_notificationf (word[1], _("File offer from: %s (%s)"), word[2], network); + } + else if (GPOINTER_TO_INT (userdata) == 2) + { + if (!is_ignored (word[2])) + show_notificationf (word[1], _("Invited to channel by: %s (%s)"), word[2], network); + } + else + { + if (!is_ignored (word[1])) + show_notificationf (word[2], _("Notice from: %s (%s)"), word[1], network); + } + } + else + show_notificationf (word[2], _("Private message from: %s (%s)"), word[1], network); + } + return HEXCHAT_EAT_NONE; +} + +static int +tray_cmd_cb (char *word[], char *word_eol[], gpointer userdata) +{ + if (word[2] && !g_ascii_strcasecmp (word[2], "-b") && word[3] && word[4]) + { + if (should_alert ()) + show_notification (word[3], word_eol[4]); + return HEXCHAT_EAT_ALL; + } + + return HEXCHAT_EAT_NONE; +} + +int +notification_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg) +{ + if (!notification_backend_init ()) + return 0; + + ph = plugin_handle; + *plugin_name = ""; + *plugin_desc = ""; + *plugin_version = ""; + + hexchat_hook_print (ph, "Channel Msg Hilight", HEXCHAT_PRI_LOWEST, incoming_hilight_cb, NULL); + hexchat_hook_print (ph, "Channel Action Hilight", HEXCHAT_PRI_LOWEST, incoming_hilight_cb, NULL); + + hexchat_hook_print (ph, "Channel Message", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL); + hexchat_hook_print (ph, "Channel Action", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL); + hexchat_hook_print (ph, "Channel Notice", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL); + + hexchat_hook_print (ph, "Private Message", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + hexchat_hook_print (ph, "Private Message to Dialog", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + hexchat_hook_print (ph, "Private Action", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + hexchat_hook_print (ph, "Private Action to Dialog", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + + /* Special events treated as priv */ + hexchat_hook_print (ph, "Notice", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (1)); + hexchat_hook_print (ph, "Invited", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (2)); + hexchat_hook_print (ph, "DCC Offer", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (3)); + + hexchat_hook_command (ph, "TRAY", HEXCHAT_PRI_HIGH, tray_cmd_cb, NULL, NULL); + + return 1; +} + + +int +notification_plugin_deinit (void) +{ + notification_backend_deinit (); + return 1; +} diff --git a/src/fe-gtk/plugin-notification.h b/src/fe-gtk/plugin-notification.h new file mode 100644 index 00000000..07ad1609 --- /dev/null +++ b/src/fe-gtk/plugin-notification.h @@ -0,0 +1,25 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef HEXCHAT_PLUGIN_NOTIFICATION_H +#define HEXCHAT_PLUGIN_NOTIFICATION_H + +int notification_plugin_init (void *, char **, char **, char **, char *); +int notification_plugin_deinit (void *); + +#endif diff --git a/src/fe-gtk/plugin-tray.c b/src/fe-gtk/plugin-tray.c index 3cd6502d..1ec8d2a3 100644 --- a/src/fe-gtk/plugin-tray.c +++ b/src/fe-gtk/plugin-tray.c @@ -34,18 +34,6 @@ #include #endif -#ifdef USE_LIBNOTIFY -#include -#ifndef NOTIFY_CHECK_VERSION -#define NOTIFY_CHECK_VERSION(x,y,z) 0 -#endif -#if NOTIFY_CHECK_VERSION(0,7,0) -#define XC_NOTIFY_NEW(a,b,c,d) notify_notification_new(a,b,c) -#else -#define XC_NOTIFY_NEW(a,b,c,d) notify_notification_new(a,b,c,d) -#endif -#endif - typedef enum /* current icon status */ { TS_NONE, @@ -154,83 +142,6 @@ fe_tray_set_tooltip (const char *text) gtk_status_icon_set_tooltip_text (sticon, text); } -void -fe_tray_set_balloon (const char *title, const char *text) -{ -#ifndef WIN32 -#if 0 - const char *argv[8]; - const char *path; - char time[16]; -#endif - WinStatus ws; - - /* no balloons if the window is focused */ - ws = tray_get_window_status (); - if ((prefs.hex_away_omit_alerts && hexchat_get_info(ph, "away")) || - (prefs.hex_gui_focus_omitalerts && ws == WS_FOCUSED)) - return; - - /* bit 1 of flags means "no balloons unless hidden/iconified" */ - if (ws != WS_HIDDEN && prefs.hex_gui_tray_quiet) - return; - - /* FIXME: this should close the current balloon */ - if (!text) - return; - -#ifdef USE_LIBNOTIFY - static int notify_text_strip_flags = STRIP_ALL; - NotifyNotification *notification; - char *notify_text, *notify_title; - - if (!notify_is_initted()) - { - GList* server_caps; - notify_init(PACKAGE_NAME); - - server_caps = notify_get_server_caps (); - if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)strcmp)) - { - notify_text_strip_flags |= STRIP_ESCMARKUP; - } - g_list_free_full (server_caps, g_free); - } - - notify_text = strip_color (text, -1, notify_text_strip_flags); - notify_title = strip_color (title, -1, STRIP_ALL); - - notification = XC_NOTIFY_NEW (notify_title, notify_text, HEXCHATSHAREDIR "/icons/hicolor/scalable/apps/hexchat.svg", NULL); - -#if NOTIFY_CHECK_VERSION(0,7,0) - notify_notification_set_hint (notification, "desktop-entry", g_variant_new_string ("hexchat")); -#endif - - g_free ((char *)notify_title); - g_free ((char *)notify_text); - - notify_notification_set_timeout (notification, prefs.hex_input_balloon_time*1000); - notify_notification_show (notification, NULL); - - g_object_unref (notification); -#endif -#endif -} - -static void -tray_set_balloonf (const char *text, const char *format, ...) -{ - va_list args; - char *buf; - - va_start (args, format); - buf = g_strdup_vprintf (format, args); - va_end (args); - - fe_tray_set_balloon (buf, text); - g_free (buf); -} - static void tray_set_tipf (const char *format, ...) { @@ -719,10 +630,6 @@ tray_hilight_cb (char *word[], void *userdata) tray_hilight_count, word[1], hexchat_get_info (ph, "channel")); } - if (prefs.hex_input_balloon_hilight) - tray_set_balloonf (word[2], _("Highlighted message from: %s (%s)"), - word[1], hexchat_get_info (ph, "channel")); - return HEXCHAT_EAT_NONE; } @@ -744,10 +651,6 @@ tray_message_cb (char *word[], void *userdata) tray_set_tipf (_(DISPLAY_NAME": %u channel messages."), tray_pub_count); } - if (prefs.hex_input_balloon_chans) - tray_set_balloonf (word[2], _("Channel message from: %s (%s)"), - word[1], hexchat_get_info (ph, "channel")); - return HEXCHAT_EAT_NONE; } @@ -775,10 +678,6 @@ tray_priv (char *from, char *text) tray_set_tipf (_(DISPLAY_NAME": %u private messages, latest from: %s (%s)"), tray_priv_count, from, network); } - - if (prefs.hex_input_balloon_priv) - tray_set_balloonf (text, _("Private message from: %s (%s)"), - from, network); } static int @@ -823,10 +722,6 @@ tray_dcc_cb (char *word[], void *userdata) tray_file_count, word[1], network); } - if (prefs.hex_input_balloon_priv && (!prefs.hex_away_omit_alerts || tray_find_away_status () != 1)) - tray_set_balloonf ("", _("File offer from: %s (%s)"), - word[1], network); - return HEXCHAT_EAT_NONE; } @@ -905,8 +800,6 @@ tray_plugin_deinit (hexchat_plugin *plugin_handle) { #ifdef WIN32 tray_cleanup (); -#elif defined(USE_LIBNOTIFY) - notify_uninit (); #endif return 1; } diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index 6d06a0fa..11261560 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -36,6 +36,7 @@ #include "pixmaps.h" #include "menu.h" #include "plugin-tray.h" +#include "notifications/notification-backend.h" #ifdef WIN32 #include "../common/fe.h" @@ -397,9 +398,47 @@ static const setting alert_settings[] = {ST_HEADER, N_("Alerts"),0,0,0}, {ST_ALERTHEAD}, -#if !defined (WIN32) && !defined (__APPLE__) - {ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0}, + + + {ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0}, + {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0}, + {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0}, +#ifdef WIN32 + {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play the \"Instant Message Notification\" system sound upon the selected events"), (void *)beeplist, 0}, +#else +#ifdef USE_LIBCANBERRA + {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play \"message-new-instant\" from the freedesktop.org sound theme upon the selected events"), (void *)beeplist, 0}, +#else + {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play a GTK beep upon the selected events"), (void *)beeplist, 0}, +#endif #endif + + {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL(hex_away_omit_alerts), 0, 0, 0}, + {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0}, + + {ST_HEADER, N_("Tray Behavior"), 0, 0, 0}, + {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4}, + {ST_TOGGLE, N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0}, + {ST_TOGGLE, N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0}, + {ST_TOGGLE, N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0}, + {ST_TOGGLE, N_("Only show notifications when hidden or iconified"), P_OFFINTNL(hex_gui_tray_quiet), 0, 0, 0}, + + {ST_HEADER, N_("Highlighted Messages"),0,0,0}, + {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1}, + + {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL(hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight}, + {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL(hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight}, + {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL(hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight}, + {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")}, + + {ST_END, 0, 0, 0, 0, 0} +}; + +static const setting alert_settings_nonotifications[] = +{ + {ST_HEADER, N_("Alerts"),0,0,0}, + + {ST_ALERTHEAD}, {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0}, #ifdef HAVE_GTK_MAC {ST_3OGGLE, N_("Bounce dock icon on:"), 0, 0, (void *)taskbarlist, 0}, @@ -422,17 +461,10 @@ static const setting alert_settings[] = {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0}, {ST_HEADER, N_("Tray Behavior"), 0, 0, 0}, -#ifdef WIN32 - {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 3}, -#else {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4}, -#endif {ST_TOGGLE, N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0}, {ST_TOGGLE, N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0}, {ST_TOGGLE, N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0}, -#ifndef WIN32 - {ST_TOGGLE, N_("Only show tray balloons when hidden or iconified"), P_OFFINTNL(hex_gui_tray_quiet), 0, 0, 0}, -#endif {ST_HEADER, N_("Highlighted Messages"),0,0,0}, {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1}, @@ -450,7 +482,7 @@ static const setting alert_settings_unity[] = {ST_HEADER, N_("Alerts"),0,0,0}, {ST_ALERTHEAD}, - {ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0}, + {ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0}, {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0}, {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0}, @@ -468,6 +500,28 @@ static const setting alert_settings_unity[] = {ST_END, 0, 0, 0, 0, 0} }; +static const setting alert_settings_unityandnonotifications[] = +{ + {ST_HEADER, N_("Alerts"), 0, 0, 0}, + + {ST_ALERTHEAD}, + {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0}, + {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0}, + + {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL (hex_away_omit_alerts), 0, 0, 0}, + {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL (hex_gui_focus_omitalerts), 0, 0, 0}, + + {ST_HEADER, N_("Highlighted Messages"), 0, 0, 0}, + {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1}, + + {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL (hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight}, + {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL (hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight}, + {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL (hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight}, + {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")}, + + {ST_END, 0, 0, 0, 0, 0} +}; + static const setting general_settings[] = { {ST_HEADER, N_("Default Messages"),0,0,0}, @@ -1832,10 +1886,18 @@ setup_create_pages (GtkWidget *box) setup_add_page (cata[8], book, setup_create_page (general_settings)); - if (unity_mode ()) + if (unity_mode () && !notification_backend_supported ()) + { + setup_add_page (cata[9], book, setup_create_page (alert_settings_unityandnonotifications)); + } + else if (unity_mode ()) { setup_add_page (cata[9], book, setup_create_page (alert_settings_unity)); } + else if (!notification_backend_supported ()) + { + setup_add_page (cata[9], book, setup_create_page (alert_settings_nonotifications)); + } else { setup_add_page (cata[9], book, setup_create_page (alert_settings)); diff --git a/src/fe-text/fe-text.c b/src/fe-text/fe-text.c index a709fe9e..7b4576da 100644 --- a/src/fe-text/fe-text.c +++ b/src/fe-text/fe-text.c @@ -902,7 +902,6 @@ void fe_tray_set_flash (const char *filename1, const char *filename2, int timeou void fe_tray_set_file (const char *filename){} void fe_tray_set_icon (feicon icon){} void fe_tray_set_tooltip (const char *text){} -void fe_tray_set_balloon (const char *title, const char *text){} void fe_userlist_update (session *sess, struct User *user){} void fe_open_chan_list (server *serv, char *filter, int do_refresh) -- cgit 1.4.1