diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index e78dd3baf8..4df2808b3d 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -37,6 +37,7 @@ set(cmake_SOURCE_FILES FreeType.cmake GStreamer010Plugin.cmake GooglePerfTools.cmake + Growl.cmake JPEG.cmake LLAddBuildTest.cmake LLAudio.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index e852cf463c..bea43f9308 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -38,6 +38,8 @@ if(WINDOWS) libapr-1.dll libaprutil-1.dll libapriconv-1.dll + lgggrowl++.dll + lgggrowl.dll ) # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables @@ -48,6 +50,8 @@ if(WINDOWS) libapr-1.dll libaprutil-1.dll libapriconv-1.dll + lgggrowl++.dll + lgggrowl.dll ) if(USE_GOOGLE_PERFTOOLS) @@ -169,6 +173,7 @@ elseif(DARWIN) libllqtwebkit.dylib libndofdev.dylib libexception_handler.dylib + libgrowl.dylib ) # fmod is statically linked on darwin @@ -236,6 +241,7 @@ elseif(LINUX) libtcmalloc.so libuuid.so.1 libssl.so.0.9.7 + libnotify.so ) if (FMOD) diff --git a/indra/cmake/FindLibnotify.cmake b/indra/cmake/FindLibnotify.cmake new file mode 100644 index 0000000000..395dac804e --- /dev/null +++ b/indra/cmake/FindLibnotify.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +# - Find libnotify +# Find the libnotify includes and library +# This module defines +# LIBNOTIFY_INCLUDE_DIR, where to find notify.h, etc. +# LIBNOTIFY_LIBRARIES, the libraries needed to use libnotify. +# LIBNOTIFY_FOUND, If false, do not try to use libnotify. +# also defined, but not for general use are +# LIBNOTIFY_LIBRARY, where to find the libnotify library. + +FIND_PATH(LIBNOTIFY_INCLUDE_DIR notify.h + PATH_SUFFIXES libnotify + ) + +SET(LIBNOTIFY_NAMES ${LIBNOTIFY_NAMES} notify) +FIND_LIBRARY(LIBNOTIFY_LIBRARY + NAMES ${LIBNOTIFY_NAMES} + ) + +IF (LIBNOTIFY_LIBRARY AND LIBNOTIFY_INCLUDE_DIR) + SET(LIBNOTIFY_LIBRARIES ${LIBNOTIFY_LIBRARY}) + SET(LIBNOTIFY_FOUND "YES") +ELSE (LIBNOTIFY_LIBRARY AND LIBNOTIFY_INCLUDE_DIR) + SET(LIBNOTIFY_FOUND "NO") +ENDIF (LIBNOTIFY_LIBRARY AND LIBNOTIFY_INCLUDE_DIR) + + +IF (LIBNOTIFY_FOUND) + IF (NOT LIBNOTIFY_FIND_QUIETLY) + MESSAGE(STATUS "Found libnotify: '${LIBNOTIFY_LIBRARIES}' and header in '${LIBNOTIFY_INCLUDE_DIR}'") + ENDIF (NOT LIBNOTIFY_FIND_QUIETLY) +ELSE (LIBNOTIFY_FOUND) + IF (LIBNOTIFY_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find libnotify library") + ENDIF (LIBNOTIFY_FIND_REQUIRED) +ENDIF (LIBNOTIFY_FOUND) + +# Deprecated declarations. +SET (NATIVE_LIBNOTIFY_INCLUDE_PATH ${LIBNOTIFY_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_LIBNOTIFY_LIB_PATH ${LIBNOTIFY_LIBRARY} PATH) + +MARK_AS_ADVANCED( + LIBNOTIFY_LIBRARY + LIBNOTIFY_INCLUDE_DIR + ) diff --git a/indra/cmake/Growl.cmake b/indra/cmake/Growl.cmake new file mode 100644 index 0000000000..7b2c9177d9 --- /dev/null +++ b/indra/cmake/Growl.cmake @@ -0,0 +1,23 @@ +# -*- cmake -*- + +# Growl is actually libnotify on linux systems. +if (STANDALONE) + set(LIBNOTIFY_FIND_REQUIRED ON) + include(FindLibnotify) + set(GROWL_INCLUDE_DIRS ${LIBNOTIFY_INCLUDE_DIR}) + set(GROWL_LIBRARY ${LIBNOTIFY_LIBRARIES}) +else (STANDALONE) + include(Prebuilt) + use_prebuilt_binary(Growl) + if (DARWIN) + set(GROWL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/Growl) + set(GROWL_LIBRARY growl) + elseif (WINDOWS) + set(GROWL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/Growl) + set(GROWL_LIBRARY lgggrowl++) + elseif (LINUX) + # Everything glib-2.0 and GTK-specific is pulled in by UI.cmake.. Ugh. + set(GROWL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/libnotify) + set(GROWL_LIBRARY notify) + endif (DARWIN) +endif (STANDALONE) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c707e4b0a3..f7076d8ed3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -41,6 +41,7 @@ include(LLKDU) include(ViewerMiscLibs) include(LLLogin) include(CMakeCopyIfDifferent) +include(Growl) include_directories( ${DBUSGLIB_INCLUDE_DIRS} @@ -65,12 +66,15 @@ include_directories( ${LSCRIPT_INCLUDE_DIRS}/lscript_compile ${LLLOGIN_INCLUDE_DIRS} ${UPDATER_INCLUDE_DIRS} + ${GROWL_INCLUDE_DIRS} ) set(viewer_SOURCE_FILES chatbar_as_cmdline.cpp kcwlinterface.cpp fscontactsfloater.cpp + growlmanager.cpp + growlnotifier.cpp llagent.cpp llagentaccess.cpp llagentcamera.cpp @@ -616,6 +620,8 @@ set(viewer_HEADER_FILES chatbar_as_cmdline.h kcwlinterface.h fscontactsfloater.h + growlmanager.h + growlnotifier.h llagent.h llagentaccess.h llagentcamera.h @@ -1144,6 +1150,11 @@ source_group("CMake Rules" FILES ViewerInstall.cmake) if (DARWIN) LIST(APPEND viewer_SOURCE_FILES llappviewermacosx.cpp) + LIST(APPEND viewer_HEADER_FILES growlnotifiermacosx-objc.h) + LIST(APPEND viewer_SOURCE_FILES growlnotifiermacosx-objc.mm) + LIST(APPEND viewer_SOURCE_FILES growlnotifiermacosx.h) + LIST(APPEND viewer_SOURCE_FILES growlnotifiermacosx.cpp) + find_library(AGL_LIBRARY AGL) find_library(APPKIT_LIBRARY AppKit) @@ -1185,6 +1196,8 @@ endif (DARWIN) if (LINUX) LIST(APPEND viewer_SOURCE_FILES llappviewerlinux.cpp) LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp) + LIST(APPEND viewer_HEADER_FILES desktopnotifierlinux.h) + LIST(APPEND viewer_SOURCE_FILES desktopnotifierlinux.cpp) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") set(viewer_LIBRARIES @@ -1194,11 +1207,13 @@ endif (LINUX) if (WINDOWS) list(APPEND viewer_SOURCE_FILES + growlnotifierwin.cpp llappviewerwin32.cpp llwindebug.cpp ) list(APPEND viewer_HEADER_FILES + growlnotifierwin.h llappviewerwin32.h llwindebug.h ) @@ -1566,6 +1581,7 @@ if (WINDOWS) ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qjpcodecsd4.dll ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qkrcodecsd4.dll ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qtwcodecsd4.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/lgggrowl.dll SLPlugin media_plugin_quicktime media_plugin_webkit @@ -1718,6 +1734,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${CRYPTO_LIBRARIES} ${LLLOGIN_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} + ${GROWL_LIBRARY} ) if (LINUX OR FIRECYG OR DARWIN) diff --git a/indra/newview/app_settings/growl_notifications.xml b/indra/newview/app_settings/growl_notifications.xml new file mode 100644 index 0000000000..276fae7971 --- /dev/null +++ b/indra/newview/app_settings/growl_notifications.xml @@ -0,0 +1,177 @@ + + + + FriendOnline + + GrowlName + Friend logged on + GrowlTitle + [NAME] + GrowlBody + came online + + FriendOffline + + GrowlName + Friend logged off + GrowlTitle + [NAME] + GrowlBody + went offline + + SystemMessageTip + + GrowlName + System Message + GrowlTitle + System Message + UseDefaultTextForBody + true + + SystemMessage + + GrowlName + System Message + GrowlTitle + System Message + UseDefaultTextForBody + true + + GroupNotice + + GrowlName + Group Notice + GrowlTitle + Group Notice + GrowlBody + [SUBJECT] + + InventoryAccepted + + GrowlName + Inventory accepted + + InventoryDeclined + + GrowlName + Inventory declined + + CallingCardAccepted + + GrowlName + Calling card accepted + + CallingCardDeclined + + GrowlName + Calling card declined + + EventNotification + + GrowlName + Event notification + GrowlTitle + Event starting soon + GrowlBody + [NAME] + + ObjectGiveItem + + GrowlName + Inventory received from object + GrowlTitle + Inventory received + UseDefaultTextForBody + true + + ObjectGiveItemUnknownUser + + GrowlName + Inventory received from object + GrowlTitle + Inventory received + UseDefaultTextForBody + true + + UserGiveItem + + GrowlName + Inventory received from a person + GrowlTitle + Inventory received + UseDefaultTextForBody + true + + OfferFriendship + + GrowlName + Friendship offer received + GrowlTitle + [NAME] is offering friendship + GrowlBody + [MESSAGE] + + OfferFriendshipNoMessage + + GrowlName + Friendship offer received + GrowlBody + [NAME] is offering friendship + + FriendshipAccepted + + GrowlName + Friendship offer accepted + + FriendshipDeclined + + GrowlName + Friendship offer declined + + RegionRestartMinute + + GrowlName + Region restart warning + GrowlTitle + Region restart in [MINUTES] minutes + GrowlBody + If you remain in this region, you will be logged out. + Urgent + true + + RegionRestartSecond + + GrowlName + Region restart warning + GrowlTitle + Region restart in [SECONDS] seconds + GrowlBody + If you remain in this region, you will be logged out. + Urgent + true + + YouHaveBeenLoggedOut + + GrowlName + You have been logged out + GrowlTitle + You have been logged out + GrowlBody + [MESSAGE] + + + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 4ff212323b..f5afd308b7 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13106,5 +13106,27 @@ Value 1 + PhoenixEnableGrowl + + Comment + Enables Growl notifications + Persist + 1 + Type + Boolean + Value + 1 + + PhoenixGrowlWhenActive + + Comment + If Growl notifications are active, show them even when the window is active. + Persist + 1 + Type + Boolean + Value + 0 + diff --git a/indra/newview/desktopnotifierlinux.cpp b/indra/newview/desktopnotifierlinux.cpp new file mode 100644 index 0000000000..ee695c5956 --- /dev/null +++ b/indra/newview/desktopnotifierlinux.cpp @@ -0,0 +1,131 @@ +/* Copyright (c) 2010 Discrete Dreamscape All rights reserved. + * + * 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. + * 3. Neither the name Discrete Dreamscape nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY DISCRETE DREAMSCAPE AND 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 DISCRETE DREAMSCAPE OR 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. + */ + +#include "llviewerprecompiledheaders.h" +#include "desktopnotifierlinux.h" + +#include "notify.h" + +const char* ICON_128 = "firestorm_icon128.png"; +const char* ICON_512 = "firestorm_icon.png"; +const gint NOTIFICATION_TIMEOUT_MS = 5000; + +static const char* icon_wholename; + +const char* Find_BMP_Resource(const char *basename) +{ + const int PATH_BUFFER_SIZE=1000; + char* path_buffer = new char[PATH_BUFFER_SIZE]; /* Flawfinder: ignore */ + + // Figure out where our BMP is living on the disk + snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s", + gDirUtilp->getAppRODataDir().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + basename); + path_buffer[PATH_BUFFER_SIZE-1] = '\0'; + + return path_buffer; +} + +DesktopNotifierLinux::DesktopNotifierLinux() +{ + if (notify_init("Firestorm Viewer")) { + LL_INFOS("DesktopNotifierLinux") << "Linux desktop notifications initialized." << LL_ENDL; + // Find the name of our notification server. I kinda don't expect it to change after the start of the program. + gchar* name = NULL; + gchar* vendor = NULL; + gchar* version = NULL; + gchar* spec = NULL; + bool info_success = notify_get_server_info(&name, &vendor, &version, &spec); + if (info_success) { + LL_INFOS("DesktopNotifierLinux") << "Server name: " << name << LL_ENDL; + LL_INFOS("DesktopNotifierLinux") << "Server vendor: " << vendor << LL_ENDL; + LL_INFOS("DesktopNotifierLinux") << "Server version: " << version << LL_ENDL; + LL_INFOS("DesktopNotifierLinux") << "Server spec: " << spec << LL_ENDL; + } + if (!info_success || strncmp("notification-daemon", name, 19)) { + // We're likely talking to notification-daemon, and I don't feel like scaling. Use a premade 128x128 icon. + icon_wholename = Find_BMP_Resource(ICON_128); + } else { + // Talking to NotifyOSD or something else. Try the 512x512 icon and let it scale on its own. + icon_wholename = Find_BMP_Resource(ICON_512); + } + LL_INFOS("DesktopNotifierLinux") << "Linux desktop notification icon: " << icon_wholename << LL_ENDL; + } else { + LL_WARNS("DesktopNotifierLinux") << "Linux desktop notifications FAILED to initialize." << LL_ENDL; + } +} + +void DesktopNotifierLinux::showNotification(const std::string& notification_title, const std::string& notification_message, const std::string& notification_type) +{ + LL_INFOS("DesktopNotifierLinux") << "New notification title: " << notification_title << LL_ENDL; + LL_INFOS("DesktopNotifierLinux") << "New notification message: " << notification_message << LL_ENDL; + LL_INFOS("DesktopNotifierLinux") << "New notification type: " << notification_type << LL_ENDL; + + static NotifyNotification* notification = notify_notification_new( + "Firestorm Viewer",//(gchar*)notification_title.c_str(), + NULL,//(gchar*)notification_message.c_str(), + icon_wholename, + NULL + ); + + notify_notification_update( + notification, + (gchar*)notification_title.c_str(), + (gchar*)notification_message.c_str(), + icon_wholename + ); + + notify_notification_set_urgency(notification, NOTIFY_URGENCY_LOW); + notify_notification_set_category(notification, (gchar*)notification_type.c_str()); + notify_notification_set_timeout(notification, NOTIFICATION_TIMEOUT_MS); // NotifyOSD ignores this, sadly. + + GError* error = NULL; + if (notify_notification_show(notification, &error)) { + LL_INFOS("DesktopNotifierLinux") << "Linux desktop notification type " << notification_type << "sent." << LL_ENDL; + } else { + LL_WARNS("DesktopNotifierLinux") << "Linux desktop notification FAILED to send. " << error->message << LL_ENDL; + } +} + +bool DesktopNotifierLinux::isUsable() +{ + return notify_is_initted(); +} + +/*void DesktopNotifierLinux::registerApplication(const std::string& application, const std::set& notificationTypes) +{ + // Do nothing for now. +}*/ + +bool DesktopNotifierLinux::needsThrottle() +{ + return false; // NotifyOSD seems to have no issues with handling spam.. How about notification-daemon? +} diff --git a/indra/newview/desktopnotifierlinux.h b/indra/newview/desktopnotifierlinux.h new file mode 100644 index 0000000000..8bd0c06f31 --- /dev/null +++ b/indra/newview/desktopnotifierlinux.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2010 Discrete Dreamscape All rights reserved. + * + * 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. + * 3. Neither the name Discrete Dreamscape nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY DISCRETE DREAMSCAPE AND 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 DISCRETE DREAMSCAPE OR 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. + */ + +#ifndef DESKTOPNOTIFIERLINUX_H +#define DESKTOPNOTIFIERLINUX_H + +#include +#include "growlnotifier.h" + +class DesktopNotifierLinux : public GrowlNotifier +{ + LOG_CLASS(DesktopNotifierLinux); +public: + DesktopNotifierLinux(); + ~DesktopNotifierLinux(){} + + void showNotification(const std::string& notification_title, const std::string& notification_message, const std::string& notificationTypes); + bool isUsable(); + //void registerApplication(const std::string& application, const std::set& notificationTypes); + bool needsThrottle(); +}; + +#endif // DESKTOPNOTIFIERLINUX_H diff --git a/indra/newview/growlmanager.cpp b/indra/newview/growlmanager.cpp new file mode 100644 index 0000000000..209321810e --- /dev/null +++ b/indra/newview/growlmanager.cpp @@ -0,0 +1,228 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#include "llviewerprecompiledheaders.h" + +#include "lldir.h" +#include "llfile.h" +#include "llnotifications.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llstartup.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" + +#include "growlmanager.h" +#include "growlnotifier.h" +#include "llwindow.h" +#include "llfocusmgr.h" + +// Platform-specific includes +#ifdef LL_DARWIN +#include "growlnotifiermacosx.h" +#elif LL_WINDOWS +#include "growlnotifierwin.h" +#elif LL_LINUX +#include "desktopnotifierlinux.h" +#endif + + +GrowlManager *gGrowlManager = NULL; + +GrowlManager::GrowlManager() : LLEventTimer(GROWL_THROTTLE_CLEANUP_PERIOD) +{ + // Create a notifier appropriate to the platform. +#ifdef LL_DARWIN + this->mNotifier = new GrowlNotifierMacOSX(); + LL_INFOS("GrowlManagerInit") << "Created GrowlNotifierMacOSX." << LL_ENDL; +#elif LL_WINDOWS + this->mNotifier = new GrowlNotifierWin(); + LL_INFOS("GrowlManagerInit") << "Created GrowlNotifierWin." << LL_ENDL; +#elif LL_LINUX + this->mNotifier = new DesktopNotifierLinux(); + LL_INFOS("GrowlManagerInit") << "Created DesktopNotifierLinux." << LL_ENDL; +#else + this->mNotifier = new GrowlNotifier(); + LL_INFOS("GrowlManagerInit") << "Created generic GrowlNotifier." << LL_ENDL; +#endif + + // Don't do anything more if Growl isn't usable. + if(!mNotifier->isUsable()) + { + LL_WARNS("GrowlManagerInit") << "Growl is unusable; bailing out." << LL_ENDL; + return; + } + + // Hook into LLNotifications... + // We hook into all of them, even though (at the time of writing) nothing uses "alert", so more notifications can be added easily. + LLNotificationChannel::buildChannel("GrowlNotifications", "Visible", LLNotificationFilters::includeEverything); + + LLNotifications::instance().getChannel("GrowlNotifications")->connectChanged(&GrowlManager::onLLNotification); + this->loadConfig(); +} + +void GrowlManager::loadConfig() +{ + std::string config_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "growl_notifications.xml"); + if(config_file == "") + { + LL_WARNS("GrowlConfig") << "Couldn't find growl_notifications.xml" << LL_ENDL; + return; + } + LL_INFOS("GrowlConfig") << "Loading growl notification config from " << config_file << LL_ENDL; + llifstream configs(config_file); + LLSD notificationLLSD; + std::set notificationTypes; + notificationTypes.insert("Keyword Alert"); + notificationTypes.insert("Instant Message received"); + if(configs.is_open()) + { + LLSDSerialize::fromXML(notificationLLSD, configs); + for(LLSD::map_iterator itr = notificationLLSD.beginMap(); itr != notificationLLSD.endMap(); ++itr) + { + GrowlNotification ntype; + ntype.growlName = itr->second.get("GrowlName").asString(); + notificationTypes.insert(ntype.growlName); + + if(itr->second.has("GrowlTitle")) + ntype.growlTitle = itr->second.get("GrowlTitle").asString(); + if(itr->second.has("GrowlBody")) + ntype.growlBody = itr->second.get("GrowlBody").asString(); + if(itr->second.has("UseDefaultTextForTitle")) + ntype.useDefaultTextForTitle = itr->second.get("UseDefaultTextForTitle").asBoolean(); + else + ntype.useDefaultTextForTitle = false; + if(itr->second.has("UseDefaultTextForBody")) + ntype.useDefaultTextForBody = itr->second.get("UseDefaultTextForBody").asBoolean(); + else + ntype.useDefaultTextForBody = false; + if(ntype.useDefaultTextForBody == false && ntype.useDefaultTextForTitle == false && + ntype.growlBody == "" && ntype.growlTitle == "") + { + ntype.useDefaultTextForBody = true; + } + this->mNotifications[itr->first] = ntype; + } + configs.close(); + + this->mNotifier->registerApplication("Firestorm Viewer", notificationTypes); + } + else + { + LL_WARNS("GrowlConfig") << "Couldn't open growl config file." << LL_ENDL; + } + +} + +void GrowlManager::notify(const std::string& notification_title, const std::string& notification_message, const std::string& notification_type) +{ + static LLCachedControl enabled(gSavedSettings, "PhoenixEnableGrowl"); + if(!enabled) + return; + + if(!shouldNotify()) + return; + + if(this->mNotifier->needsThrottle()) + { + U64 now = LLTimer::getTotalTime(); + if(mTitleTimers.find(notification_title) != mTitleTimers.end()) + { + if(mTitleTimers[notification_title] > now - GROWL_THROTTLE_TIME) + { + LL_WARNS("GrowlNotify") << "Discarded notification with title '" << notification_title << "' - spam ._." << LL_ENDL; + mTitleTimers[notification_title] = now; + return; + } + } + mTitleTimers[notification_title] = now; + } + this->mNotifier->showNotification(notification_title, notification_message.substr(0, GROWL_MAX_BODY_LENGTH), notification_type); +} + +BOOL GrowlManager::tick() +{ + mTitleTimers.clear(); + return false; +} + +bool GrowlManager::onLLNotification(const LLSD& notice) +{ + if(notice["sigtype"].asString() != "add") + return false; + static LLCachedControl enabled(gSavedSettings, "PhoenixEnableGrowl"); + if(!enabled) + return false; + if(!shouldNotify()) + return false; + LLNotificationPtr notification = LLNotifications::instance().find(notice["id"].asUUID()); + std::string name = notification->getName(); + LLSD substitutions = notification->getSubstitutions(); + if(LLStartUp::getStartupState() < STATE_STARTED) + { + LL_WARNS("GrowlLLNotification") << "GrowlManager discarded a notification (" << name << ") - too early." << LL_ENDL; + return false; + } + if(gGrowlManager->mNotifications.find(name) != gGrowlManager->mNotifications.end()) + { + GrowlNotification* growl_notification = &gGrowlManager->mNotifications[name]; + std::string body = ""; + std::string title = ""; + if(growl_notification->useDefaultTextForTitle) + title = notification->getMessage(); + else if(growl_notification->growlTitle != "") + { + LLStringUtil::format(growl_notification->growlTitle, substitutions); + title = growl_notification->growlTitle; + } + if(growl_notification->useDefaultTextForBody) + body = notification->getMessage(); + else if(growl_notification->growlBody != "") + { + LLStringUtil::format(growl_notification->growlBody, substitutions); + body = growl_notification->growlBody; + } + LL_INFOS("GrowlLLNotification") << "Notice: " << title << ": " << body << LL_ENDL; + gGrowlManager->notify(title, body, growl_notification->growlName); + } + return false; +} + +bool GrowlManager::shouldNotify() +{ + // This magic stolen from llappviewer.cpp. LLViewerWindow::getActive lies. + static LLCachedControl activated(gSavedSettings, "PhoenixGrowlWhenActive"); + return (activated || (!gViewerWindow->mWindow->getVisible() || !gFocusMgr.getAppHasFocus())); +} + +void GrowlManager::InitiateManager() +{ + gGrowlManager = new GrowlManager(); +} + diff --git a/indra/newview/growlmanager.h b/indra/newview/growlmanager.h new file mode 100644 index 0000000000..14ebea5b73 --- /dev/null +++ b/indra/newview/growlmanager.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#ifndef GROWLMANAGER_H +#define GROWLMANAGER_H +#include "growlnotifier.h" +#include "lleventtimer.h" +#include + +struct GrowlNotification +{ + std::string growlName; + std::string growlTitle; + std::string growlBody; + bool useDefaultTextForTitle; + bool useDefaultTextForBody; +}; + +const U64 GROWL_THROTTLE_TIME = 1000000; // Maximum spam rate (in microseconds). +const F32 GROWL_THROTTLE_CLEANUP_PERIOD = 300; // How often we clean up the list (in seconds). +const int GROWL_MAX_BODY_LENGTH = 255; // Arbitrary. + +class GrowlManager : public LLEventTimer +{ + LOG_CLASS(GrowlManager); +public: + + GrowlManager(); + void notify(const std::string& notification_title, const std::string& notification_message, const std::string& notification_type); + BOOL tick(); + + static void InitiateManager(); +private: + GrowlNotifier *mNotifier; + std::map mNotifications; + std::map mTitleTimers; + + void loadConfig(); + static bool onLLNotification(const LLSD& notice); + static inline bool shouldNotify(); +}; + +extern GrowlManager *gGrowlManager; + +#endif // GROWLMANAGER_H diff --git a/indra/newview/growlnotifier.cpp b/indra/newview/growlnotifier.cpp new file mode 100644 index 0000000000..300f0ebe31 --- /dev/null +++ b/indra/newview/growlnotifier.cpp @@ -0,0 +1,60 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#include "llviewerprecompiledheaders.h" +#include "growlnotifier.h" + +GrowlNotifier::GrowlNotifier() +{ + // Nothing much? +} +GrowlNotifier::~GrowlNotifier() +{ + +} + +void GrowlNotifier::showNotification(const std::string& notification_title, const std::string& notification_message, const std::string& notification_type) +{ + //LL_WARNS("GrowlNotifierGeneric") << "Growl notification failed." << LL_ENDL; +} + +bool GrowlNotifier::isUsable() +{ + return false; // Dummy implementation is not usable, obviously. +} + +void GrowlNotifier::registerApplication(const std::string& application, const std::set& notificationTypes) +{ + //nothing special +} + +bool GrowlNotifier::needsThrottle() +{ + return true; // Throttling is on by default. +} diff --git a/indra/newview/growlnotifier.h b/indra/newview/growlnotifier.h new file mode 100644 index 0000000000..92b4edce1d --- /dev/null +++ b/indra/newview/growlnotifier.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#ifndef GROWLNOTIFIER_H +#define GROWLNOTIFIER_H + +#include + +class GrowlNotifier +{ +public: + LOG_CLASS(GrowlNotifier); + GrowlNotifier(); + virtual ~GrowlNotifier(); + virtual void showNotification(const std::string& notification_title, const std::string& notification_message, const std::string& notification_type); + virtual bool isUsable(); + virtual void registerApplication(const std::string& application, const std::set& notificationTypes); + virtual bool needsThrottle(); +}; + +#endif // GROWLNOTIFIER_H diff --git a/indra/newview/growlnotifiermacosx-objc.h b/indra/newview/growlnotifiermacosx-objc.h new file mode 100644 index 0000000000..3ad870dbb0 --- /dev/null +++ b/indra/newview/growlnotifiermacosx-objc.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#ifndef GROWLNOTIFIERMACOSX_OBJC_H +#define GROWLNOTIFIERMACOSX_OBJC_H +#include +#include + +void growlApplicationBridgeNotify(const std::string& withTitle, const std::string& description, const std::string& notificationName, + void *iconData, unsigned int iconDataSize, int priority, bool isSticky); +void growlApplicationBridgeInit(); +void growlApplicationBridgeRegister(const std::string& appname, const std::set& notifications); +bool growlApplicationBridgeIsGrowlInstalled(); + +#endif // GROWLNOTIFIERMACOSX_OBJC_H diff --git a/indra/newview/growlnotifiermacosx-objc.mm b/indra/newview/growlnotifiermacosx-objc.mm new file mode 100644 index 0000000000..153ae122ca --- /dev/null +++ b/indra/newview/growlnotifiermacosx-objc.mm @@ -0,0 +1,78 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#import "growlnotifiermacosx-objc.h" +#import +#import "Growl/Growl.h" + +@interface FirestormBridge : NSObject + +void growlApplicationBridgeNotify(const std::string& withTitle, const std::string& description, const std::string& notificationName, + void *iconData, unsigned int iconDataSize, int priority, bool isSticky) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [GrowlApplicationBridge notifyWithTitle:[NSString stringWithCString:withTitle.c_str() encoding:NSUTF8StringEncoding] + description:[NSString stringWithCString:description.c_str() encoding:NSUTF8StringEncoding] + notificationName:[NSString stringWithCString:notificationName.c_str() encoding:NSUTF8StringEncoding] + iconData:(iconData == NULL ? nil : [NSData dataWithBytes:iconData length:iconDataSize]) + priority:priority + isSticky:isSticky + clickContext:nil + ]; + [pool release]; +} + +void growlApplicationBridgeInit() { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +// [GrowlApplicationBridge setGrowlDelegate:@""]; + [pool release]; +} + +bool growlApplicationBridgeIsGrowlInstalled() { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + bool installed = [GrowlApplicationBridge isGrowlInstalled]; + [pool release]; + return installed; +} + +void growlApplicationBridgeRegister(const std::string& appname, const std::set& notifications) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSMutableArray *notificationArray = [[[NSMutableArray alloc] init] autorelease]; + for(std::set::iterator itr = notifications.begin(); itr != notifications.end(); ++itr) { + [notificationArray addObject:[NSString stringWithCString:itr->c_str()]]; + } + [GrowlApplicationBridge registerWithDictionary:[NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithCString:appname.c_str()], GROWL_APP_NAME, + notificationArray, GROWL_NOTIFICATIONS_ALL, + notificationArray, GROWL_NOTIFICATIONS_DEFAULT, + nil]]; + [pool release]; +} + +@end diff --git a/indra/newview/growlnotifiermacosx.cpp b/indra/newview/growlnotifiermacosx.cpp new file mode 100644 index 0000000000..32da34aaba --- /dev/null +++ b/indra/newview/growlnotifiermacosx.cpp @@ -0,0 +1,55 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#include "llviewerprecompiledheaders.h" +#include "growlnotifiermacosx.h" +#include "growlnotifiermacosx-objc.h" + +GrowlNotifierMacOSX::GrowlNotifierMacOSX() +{ + // Work around a Growl 1.1 bug whereby the app bridge *requires* a delegate. + growlApplicationBridgeInit(); + LL_INFOS("GrowlNotifierOSX") << "OS X growl notifications initialised." << LL_ENDL; +} + +void GrowlNotifierMacOSX::showNotification(const std::string& notification_title, const std::string& notification_message, + const std::string& notification_type) +{ + growlApplicationBridgeNotify(notification_title, notification_message, notification_type, NULL, 0, 0, false); +} + +bool GrowlNotifierMacOSX::isUsable() +{ + return growlApplicationBridgeIsGrowlInstalled(); +} + +void GrowlNotifierMacOSX::registerApplication(const std::string& application, const std::set& notificationTypes) +{ + growlApplicationBridgeRegister(application, notificationTypes); +} \ No newline at end of file diff --git a/indra/newview/growlnotifiermacosx.h b/indra/newview/growlnotifiermacosx.h new file mode 100644 index 0000000000..5afe063d6f --- /dev/null +++ b/indra/newview/growlnotifiermacosx.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2010 Katharine Berry All rights reserved. + * + * 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. + * 3. Neither the name Katharine Berry nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY AND 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 KATHARINE BERRY OR 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. + */ + +#ifndef GROWLNOTIFIERMACOSX_H +#define GROWLNOTIFIERMACOSX_H + +#include +#include "growlnotifier.h" + +class GrowlNotifierMacOSX : public GrowlNotifier +{ +public: + GrowlNotifierMacOSX(); + ~GrowlNotifierMacOSX(){} + + void showNotification(const std::string& notification_title, const std::string& notification_message, const std::string& notificationTypes); + bool isUsable(); + void registerApplication(const std::string& application, const std::set& notificationTypes); +}; + +#endif // GROWLNOTIFIERMACOSX_H diff --git a/indra/newview/growlnotifierwin.cpp b/indra/newview/growlnotifierwin.cpp new file mode 100644 index 0000000000..93c1650574 --- /dev/null +++ b/indra/newview/growlnotifierwin.cpp @@ -0,0 +1,78 @@ +/* Copyright (c) 2009 +* +* Greg Hendrickson (LordGregGreg Back). All rights reserved. +* +* 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. +* 3. Neither the name Modular Systems nor the names of its contributors +* may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND 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 MODULAR SYSTEMS OR 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. +*/ + + +#include "llviewerprecompiledheaders.h" +#include "growlnotifierwin.h" +#include "llviewercontrol.h" + +GrowlNotifierWin::GrowlNotifierWin():applicationName("") +{ + LL_INFOS("GrowlNotifierWin") << "Windows growl notifications initialised." << LL_ENDL; + +} +void GrowlNotifierWin::registerApplication(const std::string& application, const std::set& notificationTypes) +{ + applicationName=application; + + char **arr = (char**)malloc(sizeof(*arr) * notificationTypes.size()); + int i = 0; + for(std::set::const_iterator it = notificationTypes.begin(); it != notificationTypes.end(); ++it, ++i) { + char *string = (char*)malloc(it->size() + 1); + strcpy(string, it->c_str()); + arr[i] = string; + } + growl = new Growl(GROWL_TCP,NULL,application.c_str(),(const char **const)arr,notificationTypes.size(), + std::string(gDirUtilp->getDefaultSkinDir()+gDirUtilp->getDirDelimiter()+ + "textures"+gDirUtilp->getDirDelimiter()+"firestorm_icon.png").c_str()); + growl->setProtocol(GROWL_UDP); + + for(i = 0; i < (int)notificationTypes.size(); ++i) { + free(arr[i]); + } + free(arr); +} +void GrowlNotifierWin::showNotification(const std::string& notification_title, const std::string& notification_message, + const std::string& notification_type) +{ + //LL_INFOS("GrowlNotifierWin") << std::string(gDirUtilp->getDefaultSkinDir()+gDirUtilp->getDirDelimiter()+"textures"+gDirUtilp->getDirDelimiter()+"phoenixicon.ico").c_str() << LL_ENDL; + growl->Notify(notification_type.c_str(),notification_title.c_str(),notification_message.c_str() + //, + //std::string("").c_str(),//url + //std::string("http://phoenixviewer.com/box/phoenixicon.ico").c_str() + ); +} + +bool GrowlNotifierWin::isUsable() +{ + //if(growl) return true; + return true; +} diff --git a/indra/newview/growlnotifierwin.h b/indra/newview/growlnotifierwin.h new file mode 100644 index 0000000000..408c2517b1 --- /dev/null +++ b/indra/newview/growlnotifierwin.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2009 +* +* Greg Hendrickson (LordGregGreg Back). All rights reserved. +* +* 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. +* 3. Neither the name Modular Systems nor the names of its contributors +* may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND 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 MODULAR SYSTEMS OR 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. +*/ + +#ifndef GROWLNOTIFIERWIN_H +#define GROWLNOTIFIERWIN_H + +#include "growlnotifier.h" +#include + +class GrowlNotifierWin : public GrowlNotifier +{ +public: + GrowlNotifierWin(); + ~GrowlNotifierWin(){} + + void showNotification(const std::string& notification_title, const std::string& notification_message, const std::string& notification_type); + bool isUsable(); + void registerApplication(const std::string& application, const std::set& notificationTypes); +private: + std::string applicationName; + Growl *growl; +}; + +#endif // GROWLNOTIFIERWIN_H diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 57ffedd697..4e31369d96 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -321,7 +321,15 @@ void LLNearbyChat::setVisible(BOOL visible) LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); if(chat_channel) { - chat_channel->removeToastsFromChannel(); + chat_channel->hideToastsFromScreen(); + } + } + else + { + LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + if(chat_channel) + { + chat_channel->showToastsOnScreen(); } } LLDockableFloater::setVisible(visible); diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index e7bfe7acc7..03ebf0d0d4 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -724,6 +724,13 @@ void LLScreenChannel::hideToastsFromScreen() (*it).toast->setVisible(FALSE); } +//-------------------------------------------------------------------------- +void LLScreenChannel::showToastsOnScreen() +{ + for(std::vector::iterator it = mToastList.begin(); it != mToastList.end(); it++) + (*it).toast->setVisible(TRUE); +} + //-------------------------------------------------------------------------- void LLScreenChannel::hideToast(const LLUUID& notification_id) { diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h index a1fdd6e32c..c3338b783d 100644 --- a/indra/newview/llscreenchannel.h +++ b/indra/newview/llscreenchannel.h @@ -77,6 +77,8 @@ public: virtual void hideToastsFromScreen() {}; // removes all toasts from a channel virtual void removeToastsFromChannel() {}; + // show toasts that were hidden by hideToastsFromScreen() + virtual void showToastsOnScreen() {}; // show all toasts in a channel virtual void redrawToasts() {}; @@ -169,6 +171,8 @@ public: void hideToastsFromScreen(); // hide toast by notification id void hideToast(const LLUUID& notification_id); + // show toasts that were hidden by hideToastsFromScreen() + void showToastsOnScreen(); /** * Closes hidden matched toasts from channel. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 4ea218ae8a..70b0c36e5d 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -199,6 +199,7 @@ #endif #include "llnotificationmanager.h" +#include "growlmanager.h" // @@ -375,6 +376,8 @@ bool idle_startup() // Initialize stuff that doesn't need data from simulators // + GrowlManager::InitiateManager(); + // [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-0.2.1d if ( (gSavedSettings.controlExists(RLV_SETTING_MAIN)) && (gSavedSettings.getBOOL(RLV_SETTING_MAIN)) ) { diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 33030aaa75..2cc9be65ac 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -117,6 +117,8 @@ #include "llnotificationmanager.h" // +#include "growlmanager.h" + #if LL_MSVC // disable boost::lexical_cast warning #pragma warning (disable:4702) @@ -2487,6 +2489,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) region_id, position, true); + + + // Notifications! + if(offline != IM_OFFLINE) + { + gGrowlManager->notify(name, message, "Instant Message received"); + } } else { @@ -2953,6 +2962,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) params.payload = payload; LLPostponedNotification::add(params, from_id, from_group); + gGrowlManager->notify(name, message, "Instant Message received"); } break; case IM_FROM_TASK_AS_ALERT: diff --git a/indra/newview/res-sdl/firestorm_icon.png b/indra/newview/res-sdl/firestorm_icon.png new file mode 100644 index 0000000000..a5e3fe25ab Binary files /dev/null and b/indra/newview/res-sdl/firestorm_icon.png differ diff --git a/indra/newview/res-sdl/firestorm_icon128.png b/indra/newview/res-sdl/firestorm_icon128.png new file mode 100644 index 0000000000..a9940a9780 Binary files /dev/null and b/indra/newview/res-sdl/firestorm_icon128.png differ diff --git a/indra/newview/skins/default/textures/firestorm_icon.png b/indra/newview/skins/default/textures/firestorm_icon.png new file mode 100644 index 0000000000..a9940a9780 Binary files /dev/null and b/indra/newview/skins/default/textures/firestorm_icon.png differ diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index e08477b33e..083b5650ce 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -341,6 +341,12 @@ class WindowsManifest(ViewerManifest): self.path("dbghelp.dll") self.enable_no_crt_manifest_check() + + #"G:\firestorm\lgpl\growl\libraries\i686-win32\lib\release\lgggrowl.dll" + if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'release'),dst="./"): + self.path("lgggrowl.dll") + self.path("lgggrowl++.dll") + self.end_prefix() # Media plugins - QuickTime if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): @@ -593,6 +599,9 @@ class DarwinManifest(ViewerManifest): self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install") + # Growl library + self.path("../../libraries/universal-darwin/lib_release/libgrowl.dylib", "Frameworks/Growl.framework/Versions/A/Growl"); + # most everything goes in the Resources directory if self.prefix(src="", dst="Resources"): super(DarwinManifest, self).construct() @@ -976,6 +985,7 @@ class Linux_i686Manifest(LinuxManifest): self.path("libalut.so") self.path("libopenal.so", "libopenal.so.1") self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname + self.path("libnotify.so.1.1.2", "libnotify.so.1") try: self.path("libkdu.so") pass diff --git a/install.xml b/install.xml index cbd00de220..5d1b6ff0f4 100644 --- a/install.xml +++ b/install.xml @@ -3,6 +3,39 @@ installables + Growl + + copyright + The Growl Project + description + A unified notification system for Mac OS X + license + bsd + packages + + darwin + + md5sum + f075e96d8e1bfdd1f518829f0d7b74af + url + http://downloads.phoenixviewer.com/growl-1.2.1-darwin.tar.gz + + windows + + md5sum + b017cc5f759eaeb862a8b94d43a39c04 + url + http://downloads.phoenixviewer.com/lggemwingrowllibraries.tar.bz2 + + linux + + md5sum + af06208ec80b1f170cc560141602e2dc + url + http://downloads.phoenixviewer.com/libnotify-0.4.4-linux-20101003.tar.bz2 + + + GL copyright