OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h" | 5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h" |
6 | 6 |
7 #include <algorithm> | |
8 | |
7 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
8 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
11 #include "chrome/browser/browser_process.h" | |
9 #include "chrome/browser/notifications/notification.h" | 12 #include "chrome/browser/notifications/notification.h" |
10 | 13 |
11 namespace { | 14 namespace { |
12 | 15 |
13 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; | 16 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; |
14 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; | 17 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; |
15 | 18 |
19 // Callback used by GLib when the "Notify" message completes for the | |
20 // first time. | |
21 void NotifyCompleteReceiver(GObject* source_object, | |
22 GAsyncResult* result, | |
23 gpointer user_data) { | |
24 GDBusProxy* proxy = G_DBUS_PROXY(source_object); | |
25 GVariant* value = g_dbus_proxy_call_finish(proxy, result, nullptr); | |
26 if (!value) { | |
27 // The message might have been cancelled, in which case | |
28 // |user_data| points to a destroyed NotificationData. | |
29 return; | |
30 } | |
31 auto* platform_bridge_linux = static_cast<NotificationPlatformBridgeLinux*>( | |
32 g_browser_process->notification_platform_bridge()); | |
33 platform_bridge_linux->NotifyCompleteInternal(user_data, value); | |
34 } | |
35 | |
16 } // namespace | 36 } // namespace |
17 | 37 |
18 // static | 38 // static |
19 NotificationPlatformBridge* NotificationPlatformBridge::Create() { | 39 NotificationPlatformBridge* NotificationPlatformBridge::Create() { |
20 GDBusProxy* notification_proxy = g_dbus_proxy_new_for_bus_sync( | 40 GDBusProxy* notification_proxy = g_dbus_proxy_new_for_bus_sync( |
21 G_BUS_TYPE_SESSION, | 41 G_BUS_TYPE_SESSION, |
22 static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | | 42 static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | |
23 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | | 43 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | |
24 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), | 44 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), |
25 nullptr, kFreedesktopNotificationsName, kFreedesktopNotificationsPath, | 45 nullptr, kFreedesktopNotificationsName, kFreedesktopNotificationsPath, |
26 kFreedesktopNotificationsName, nullptr, nullptr); | 46 kFreedesktopNotificationsName, nullptr, nullptr); |
27 if (!notification_proxy) | 47 if (!notification_proxy) |
28 return nullptr; | 48 return nullptr; |
29 return new NotificationPlatformBridgeLinux(notification_proxy); | 49 return new NotificationPlatformBridgeLinux(notification_proxy); |
30 } | 50 } |
31 | 51 |
52 struct NotificationPlatformBridgeLinux::NotificationData { | |
53 NotificationData(const std::string& notification_id, | |
54 const std::string& profile_id, | |
55 bool is_incognito) | |
56 : notification_id(notification_id), | |
57 profile_id(profile_id), | |
58 is_incognito(is_incognito) {} | |
59 | |
60 ~NotificationData() { | |
61 if (cancellable) | |
62 g_cancellable_cancel(cancellable); | |
63 } | |
64 | |
65 // The ID used by the notification server. Will be 0 until the | |
66 // first "Notify" message completes. | |
67 uint32_t dbus_id = 0; | |
68 | |
69 // Same parameters used by NotificationPlatformBridge::Display(). | |
70 const std::string notification_id; | |
71 const std::string profile_id; | |
72 const bool is_incognito; | |
73 | |
74 // Used to cancel the initial "Notify" message so we don't call | |
75 // NotificationPlatformBridgeLinux::NotifyCompleteInternal() with a | |
76 // destroyed Notification. | |
77 ScopedGObject<GCancellable> cancellable; | |
78 | |
79 // If not null, the data to update the notification with once | |
80 // |dbus_id| becomes available. | |
81 std::unique_ptr<Notification> update_data; | |
82 NotificationCommon::Type update_type = NotificationCommon::TYPE_MAX; | |
83 | |
84 // If true, indicates the notification should be closed once | |
85 // |dbus_id| becomes available. | |
86 bool should_close = false; | |
87 }; | |
88 | |
32 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( | 89 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( |
33 GDBusProxy* notification_proxy) | 90 GDBusProxy* notification_proxy) |
34 : notification_proxy_(notification_proxy) {} | 91 : notification_proxy_(notification_proxy) {} |
35 | 92 |
36 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() { | 93 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() {} |
37 g_object_unref(notification_proxy_); | |
38 } | |
39 | 94 |
40 void NotificationPlatformBridgeLinux::Display( | 95 void NotificationPlatformBridgeLinux::Display( |
41 NotificationCommon::Type notification_type, | 96 NotificationCommon::Type notification_type, |
42 const std::string& notification_id, | 97 const std::string& notification_id, |
43 const std::string& profile_id, | 98 const std::string& profile_id, |
44 bool is_incognito, | 99 bool is_incognito, |
45 const Notification& notification) { | 100 const Notification& notification) { |
46 // TODO(thomasanderson): Add a complete implementation. | 101 NotificationData* data = FindNotificationData(notification_id, profile_id); |
47 g_dbus_proxy_call( | 102 if (data) { |
48 notification_proxy_, "Notify", | 103 // Update an existing notification. |
49 g_variant_new("(susssasa{sv}i)", "", 0, "", | 104 if (data->dbus_id) { |
50 base::UTF16ToUTF8(notification.title()).c_str(), | 105 NotifyNow(data->dbus_id, notification_type, notification, nullptr, |
51 base::UTF16ToUTF8(notification.message()).c_str(), nullptr, | 106 nullptr, nullptr); |
52 nullptr, -1), | 107 } else { |
53 G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr); | 108 data->update_type = notification_type; |
109 data->update_data = base::MakeUnique<Notification>(notification); | |
110 } | |
111 } else { | |
112 // Send the notification for the first time. | |
113 data = new NotificationData(notification_id, profile_id, is_incognito); | |
114 data->cancellable.reset(g_cancellable_new()); | |
115 notifications_.emplace(data, base::WrapUnique(data)); | |
116 NotifyNow(0, notification_type, notification, data->cancellable, | |
117 NotifyCompleteReceiver, data); | |
118 } | |
54 } | 119 } |
55 | 120 |
56 void NotificationPlatformBridgeLinux::Close( | 121 void NotificationPlatformBridgeLinux::Close( |
57 const std::string& profile_id, | 122 const std::string& profile_id, |
58 const std::string& notification_id) { | 123 const std::string& notification_id) { |
59 NOTIMPLEMENTED(); | 124 NotificationData* data = FindNotificationData(notification_id, profile_id); |
125 if (!data) | |
126 return; | |
127 if (data->dbus_id) { | |
128 CloseNow(data->dbus_id); | |
129 notifications_.erase(data); | |
130 } else { | |
131 data->should_close = true; | |
132 } | |
60 } | 133 } |
61 | 134 |
62 void NotificationPlatformBridgeLinux::GetDisplayed( | 135 void NotificationPlatformBridgeLinux::GetDisplayed( |
63 const std::string& profile_id, | 136 const std::string& profile_id, |
64 bool incognito, | 137 bool incognito, |
65 const DisplayedNotificationsCallback& callback) const { | 138 const DisplayedNotificationsCallback& callback) const { |
66 callback.Run(base::MakeUnique<std::set<std::string>>(), false); | 139 callback.Run(base::MakeUnique<std::set<std::string>>(), false); |
67 } | 140 } |
141 | |
142 void NotificationPlatformBridgeLinux::NotifyCompleteInternal(gpointer user_data, | |
143 GVariant* value) { | |
144 NotificationData* data = reinterpret_cast<NotificationData*>(user_data); | |
145 if (notifications_.find(data) == notifications_.end()) | |
Lei Zhang
2017/04/06 19:59:33
!base::ContainsKey(notifications_, data) ?
Tom (Use chromium acct)
2017/04/06 22:28:56
Done.
| |
146 return; | |
147 data->cancellable.reset(); | |
148 if (value && g_variant_is_of_type(value, G_VARIANT_TYPE("(u)"))) | |
149 g_variant_get(value, "(u)", &data->dbus_id); | |
150 | |
151 if (!data->dbus_id) { | |
152 // There was some sort of error with creating the notification. | |
153 notifications_.erase(data); | |
154 } else if (data->should_close) { | |
155 CloseNow(data->dbus_id); | |
156 notifications_.erase(data); | |
157 } else if (data->update_data) { | |
158 NotifyNow(data->dbus_id, data->update_type, *data->update_data, nullptr, | |
159 nullptr, nullptr); | |
160 data->update_data.reset(); | |
161 } | |
162 } | |
163 | |
164 void NotificationPlatformBridgeLinux::NotifyNow( | |
165 uint32_t dbus_id, | |
166 NotificationCommon::Type notification_type, | |
167 const Notification& notification, | |
168 GCancellable* cancellable, | |
169 GAsyncReadyCallback callback, | |
170 gpointer user_data) { | |
171 // TODO(thomasanderson): Add a complete implementation. | |
172 const std::string title = base::UTF16ToUTF8(notification.title()); | |
173 const std::string message = base::UTF16ToUTF8(notification.message()); | |
174 GVariant* parameters = | |
175 g_variant_new("(susssasa{sv}i)", "", dbus_id, "", title.c_str(), | |
176 message.c_str(), nullptr, nullptr, -1); | |
177 g_dbus_proxy_call(notification_proxy_, "Notify", parameters, | |
178 G_DBUS_CALL_FLAGS_NONE, -1, cancellable, callback, | |
179 user_data); | |
180 } | |
181 | |
182 void NotificationPlatformBridgeLinux::CloseNow(uint32_t dbus_id) { | |
183 g_dbus_proxy_call(notification_proxy_, "CloseNotification", | |
184 g_variant_new("(u)", dbus_id), G_DBUS_CALL_FLAGS_NONE, -1, | |
185 nullptr, nullptr, nullptr); | |
186 } | |
187 | |
188 NotificationPlatformBridgeLinux::NotificationData* | |
189 NotificationPlatformBridgeLinux::FindNotificationData( | |
190 const std::string& notification_id, | |
191 const std::string& profile_id) { | |
192 for (const auto& pair : notifications_) { | |
193 NotificationData* data = pair.first; | |
194 if (data->notification_id == notification_id && | |
195 data->profile_id == profile_id) { | |
196 return data; | |
197 } | |
198 } | |
199 | |
200 return nullptr; | |
201 } | |
OLD | NEW |