diff --git a/brightray/browser/linux/notification_presenter_linux.cc b/brightray/browser/linux/notification_presenter_linux.cc index 56746bbf162..6848ce5111c 100644 --- a/brightray/browser/linux/notification_presenter_linux.cc +++ b/brightray/browser/linux/notification_presenter_linux.cc @@ -17,24 +17,9 @@ namespace brightray { namespace { -struct NotificationID { - NotificationID( - int render_process_id, - int render_view_id, - int notification_id) - : render_process_id(render_process_id), - render_view_id(render_view_id), - notification_id(notification_id) { - } - - std::string GetID() { - return base::StringPrintf("%d:%d:%d", render_process_id, render_view_id, notification_id); - } - - int render_process_id; - int render_view_id; - int notification_id; -}; +const char *kRenderProcessIDKey = "RenderProcessID"; +const char *kRenderViewIDKey = "RenderViewID"; +const char *kNotificationIDKey = "NotificationID"; void log_and_clear_error(GError *error, const char *context) { if (error) { @@ -43,20 +28,28 @@ void log_and_clear_error(GError *error, const char *context) { } } -void closed_cb(NotifyNotification *notification, NotificationID *ID) { - auto host = content::RenderViewHost::FromID(ID->render_process_id, ID->render_view_id); - if (host) host->DesktopNotificationPostClick(ID->notification_id); +void closed_cb(NotifyNotification *notification, NotificationPresenterLinux *obj) { + int render_process_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), kRenderProcessIDKey)); + int render_view_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), kRenderViewIDKey)); + int notification_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), kNotificationIDKey)); + LOG(INFO) << "closed_cb: process=" << render_process_id + << " view=" << render_view_id + << " notification=" << notification_id + << " reason=" << notify_notification_get_closed_reason(notification); + obj->RemoveNotification(notification); } -NotifyNotification *CreateUserNotification( - const content::ShowDesktopNotificationHostMsgParams& params, - int render_process_id, - int render_view_id) { - std::string title = base::UTF16ToUTF8(params.title); - std::string body = base::UTF16ToUTF8(params.body); - NotifyNotification *notification = notify_notification_new(title.c_str(), body.c_str(), NULL); - - return notification; +void action_cb(NotifyNotification *notification, const char *action, NotificationPresenterLinux *obj) { + int render_process_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), kRenderProcessIDKey)); + int render_view_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), kRenderViewIDKey)); + int notification_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), kNotificationIDKey)); + LOG(INFO) << "action_cb: process=" << render_process_id + << " view=" << render_view_id + << " notification=" << notification_id + << " action=\"" << action << '"'; + auto host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host) host->DesktopNotificationPostClick(notification_id); + obj->RemoveNotification(notification); } } @@ -68,58 +61,85 @@ NotificationPresenter* NotificationPresenter::Create() { return new NotificationPresenterLinux; } +NotificationPresenterLinux::NotificationPresenterLinux() : notifications_(NULL) { } + +NotificationPresenterLinux::~NotificationPresenterLinux() { + if (notifications_) { + for (GList *p = notifications_; p != NULL; p = p->next) { + g_object_unref(G_OBJECT(p->data)); + } + g_list_free(notifications_); + } +} + void NotificationPresenterLinux::ShowNotification( const content::ShowDesktopNotificationHostMsgParams& params, int render_process_id, int render_view_id) { - DLOG(INFO) << "ShowNotification: process=" << render_process_id - << " view=" << render_view_id - << " notification=" << params.notification_id - << " title=\"" << params.title << '"' - << " body=\"" << params.body << '"'; - NotifyNotification *notification = CreateUserNotification(params, render_process_id, render_view_id); - NotificationID ID(render_process_id, render_view_id, params.notification_id); - std::pair p = notification_map_.insert(std::make_pair(ID.GetID(), notification)); + LOG(INFO) << "ShowNotification: process=" << render_process_id + << " view=" << render_view_id + << " notification=" << params.notification_id + << " title=\"" << params.title << '"' + << " body=\"" << params.body << '"'; - g_signal_connect(notification, "closed", G_CALLBACK(closed_cb), new NotificationID(ID)); // FIXME: closure to free it + std::string title = base::UTF16ToUTF8(params.title); + std::string body = base::UTF16ToUTF8(params.body); + NotifyNotification *notification = notify_notification_new(title.c_str(), body.c_str(), NULL); + g_object_set_data(G_OBJECT(notification), kRenderProcessIDKey, GINT_TO_POINTER(render_process_id)); + g_object_set_data(G_OBJECT(notification), kRenderViewIDKey, GINT_TO_POINTER(render_view_id)); + g_object_set_data(G_OBJECT(notification), kNotificationIDKey, GINT_TO_POINTER(params.notification_id)); + g_signal_connect(notification, "closed", G_CALLBACK(closed_cb), this); + notify_notification_add_action(notification, "default", "View", (NotifyActionCallback)action_cb, this, NULL); + + notifications_ = g_list_append(notifications_, notification); GError *error = NULL; notify_notification_show(notification, &error); log_and_clear_error(error, "notify_notification_show"); - auto host = content::RenderViewHost::FromID(ID.render_process_id, ID.render_view_id); + auto host = content::RenderViewHost::FromID(render_process_id, render_view_id); if (!host) return; - host->DesktopNotificationPostDisplay(ID.notification_id); + host->DesktopNotificationPostDisplay(params.notification_id); } void NotificationPresenterLinux::CancelNotification( int render_process_id, int render_view_id, int notification_id) { - DLOG(INFO) << "CancelNotification: process=" << render_process_id - << " view=" << render_view_id - << " notification=" << notification_id; + LOG(INFO) << "CancelNotification: process=" << render_process_id + << " view=" << render_view_id + << " notification=" << notification_id; - auto found = notification_map_.find(NotificationID(render_process_id, render_view_id, notification_id).GetID()); - if (found == notification_map_.end()) + NotifyNotification *notification = NULL; + for (GList *p = notifications_; p != NULL; p = p->next) { + if (render_process_id == GPOINTER_TO_INT(g_object_get_data(G_OBJECT(p->data), kRenderProcessIDKey)) + && render_view_id == GPOINTER_TO_INT(g_object_get_data(G_OBJECT(p->data), kRenderViewIDKey)) + && notification_id == GPOINTER_TO_INT(g_object_get_data(G_OBJECT(p->data), kNotificationIDKey))) { + notification = (NotifyNotification*)p->data; + notifications_ = g_list_delete_link(notifications_, p); + break; + } + } + if (!notification) return; - auto notification = found->second; - - notification_map_.erase(found); - GError *error = NULL; notify_notification_close(notification, &error); log_and_clear_error(error, "notify_notification_close"); + g_object_unref(notification); - NotificationID ID(render_process_id, render_view_id, notification_id); auto host = content::RenderViewHost::FromID(render_process_id, render_view_id); if (!host) return; - host->DesktopNotificationPostClose(ID.notification_id, false); + host->DesktopNotificationPostClose(notification_id, false); +} + +void NotificationPresenterLinux::RemoveNotification(NotifyNotification *former_notification) { + notifications_ = g_list_remove(notifications_, former_notification); + g_object_unref(former_notification); } } diff --git a/brightray/browser/linux/notification_presenter_linux.h b/brightray/browser/linux/notification_presenter_linux.h index b3d77dc63e6..4b6344cfbe7 100644 --- a/brightray/browser/linux/notification_presenter_linux.h +++ b/brightray/browser/linux/notification_presenter_linux.h @@ -17,6 +17,9 @@ namespace brightray { class NotificationPresenterLinux : public NotificationPresenter { public: + NotificationPresenterLinux(); + ~NotificationPresenterLinux(); + virtual void ShowNotification( const content::ShowDesktopNotificationHostMsgParams&, int render_process_id, @@ -26,9 +29,10 @@ class NotificationPresenterLinux : public NotificationPresenter { int render_view_id, int notification_id) OVERRIDE; + void RemoveNotification(NotifyNotification *former_notification); + private: - typedef std::map NotificationMap; - NotificationMap notification_map_; + GList *notifications_; }; } // namespace brightray