Browse Source

Merge pull request #5582 from electron/notification-user-info

Pass userInfo in systemPreferences.subscribeNotification
Cheng Zhao 9 years ago
parent
commit
d2a567d6ab

+ 1 - 0
atom/browser/api/atom_api_system_preferences.cc

@@ -5,6 +5,7 @@
 #include "atom/browser/api/atom_api_system_preferences.h"
 
 #include "atom/common/native_mate_converters/callback.h"
+#include "atom/common/native_mate_converters/value_converter.h"
 #include "atom/common/node_includes.h"
 #include "native_mate/dictionary.h"
 

+ 10 - 1
atom/browser/api/atom_api_system_preferences.h

@@ -11,6 +11,10 @@
 #include "base/callback.h"
 #include "native_mate/handle.h"
 
+namespace base {
+class DictionaryValue;
+}
+
 namespace atom {
 
 namespace api {
@@ -22,11 +26,16 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences> {
   static void BuildPrototype(v8::Isolate* isolate,
                              v8::Local<v8::ObjectTemplate> prototype);
 
+#if defined(OS_MACOSX)
+  using NotificationCallback = base::Callback<
+      void(const std::string&, const base::DictionaryValue&)>;
+#endif
+
 #if defined(OS_WIN)
   bool IsAeroGlassEnabled();
 #elif defined(OS_MACOSX)
   int SubscribeNotification(const std::string& name,
-                            const base::Closure& callback);
+                            const NotificationCallback& callback);
   void UnsubscribeNotification(int id);
   v8::Local<v8::Value> GetUserDefault(const std::string& name,
                                       const std::string& type);

+ 16 - 4
atom/browser/api/atom_api_system_preferences_mac.mm

@@ -8,8 +8,10 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "atom/browser/mac/dict_util.h"
 #include "atom/common/native_mate_converters/gurl_converter.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/values.h"
 #include "net/base/mac/url_conversions.h"
 
 namespace atom {
@@ -25,16 +27,26 @@ std::map<int, id> g_id_map;
 
 }  // namespace
 
-int SystemPreferences::SubscribeNotification(const std::string& name,
-                                             const base::Closure& callback) {
+int SystemPreferences::SubscribeNotification(
+    const std::string& name, const NotificationCallback& callback) {
   int request_id = g_next_id++;
-  __block base::Closure copied_callback = callback;
+  __block NotificationCallback copied_callback = callback;
   g_id_map[request_id] = [[NSDistributedNotificationCenter defaultCenter]
       addObserverForName:base::SysUTF8ToNSString(name)
       object:nil
       queue:nil
       usingBlock:^(NSNotification* notification) {
-        copied_callback.Run();
+        scoped_ptr<base::DictionaryValue> user_info =
+            NSDictionaryToDictionaryValue(notification.userInfo);
+        if (user_info) {
+          copied_callback.Run(
+              base::SysNSStringToUTF8(notification.name),
+              *user_info);
+        } else {
+          copied_callback.Run(
+              base::SysNSStringToUTF8(notification.name),
+              base::DictionaryValue());
+        }
       }
   ];
   return request_id;

+ 87 - 11
atom/browser/mac/dict_util.mm

@@ -4,13 +4,55 @@
 
 #include "atom/browser/mac/dict_util.h"
 
-#include "base/mac/scoped_nsobject.h"
-#include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
 
 namespace atom {
 
+namespace {
+
+scoped_ptr<base::ListValue> NSArrayToListValue(NSArray* arr) {
+  if (!arr)
+    return nullptr;
+
+  scoped_ptr<base::ListValue> result(new base::ListValue);
+  for (id value in arr) {
+    if ([value isKindOfClass:[NSString class]]) {
+      result->AppendString(base::SysNSStringToUTF8(value));
+    } else if ([value isKindOfClass:[NSNumber class]]) {
+      const char* objc_type = [value objCType];
+      if (strcmp(objc_type, @encode(BOOL)) == 0 ||
+          strcmp(objc_type, @encode(char)) == 0)
+        result->AppendBoolean([value boolValue]);
+      else if (strcmp(objc_type, @encode(double)) == 0 ||
+               strcmp(objc_type, @encode(float)) == 0)
+        result->AppendDouble([value doubleValue]);
+      else
+        result->AppendInteger([value intValue]);
+    } else if ([value isKindOfClass:[NSArray class]]) {
+      scoped_ptr<base::ListValue> sub_arr = NSArrayToListValue(value);
+      if (sub_arr)
+        result->Append(std::move(sub_arr));
+      else
+        result->Append(base::Value::CreateNullValue());
+    } else if ([value isKindOfClass:[NSDictionary class]]) {
+      scoped_ptr<base::DictionaryValue> sub_dict =
+          NSDictionaryToDictionaryValue(value);
+      if (sub_dict)
+        result->Append(std::move(sub_dict));
+      else
+        result->Append(base::Value::CreateNullValue());
+    } else {
+      result->AppendString(base::SysNSStringToUTF8([value description]));
+    }
+  }
+
+  return result;
+}
+
+}  // namespace
+
 NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value) {
   std::string json;
   if (!base::JSONWriter::Write(value, &json))
@@ -26,17 +68,51 @@ NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value)
 
 scoped_ptr<base::DictionaryValue> NSDictionaryToDictionaryValue(
     NSDictionary* dict) {
-  NSData* data = [NSJSONSerialization dataWithJSONObject:dict
-                                                 options:0
-                                                   error:nil];
-  if (!data)
+  if (!dict)
     return nullptr;
 
-  base::scoped_nsobject<NSString> json =
-      [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
-  scoped_ptr<base::Value> value =
-      base::JSONReader::Read([json UTF8String]);
-  return base::DictionaryValue::From(std::move(value));
+  scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
+  for (id key in dict) {
+    std::string str_key = base::SysNSStringToUTF8(
+        [key isKindOfClass:[NSString class]] ? key : [key description]);
+
+    id value = [dict objectForKey:key];
+    if ([value isKindOfClass:[NSString class]]) {
+      result->SetStringWithoutPathExpansion(
+          str_key, base::SysNSStringToUTF8(value));
+    } else if ([value isKindOfClass:[NSNumber class]]) {
+      const char* objc_type = [value objCType];
+      if (strcmp(objc_type, @encode(BOOL)) == 0 ||
+          strcmp(objc_type, @encode(char)) == 0)
+        result->SetBooleanWithoutPathExpansion(str_key, [value boolValue]);
+      else if (strcmp(objc_type, @encode(double)) == 0 ||
+               strcmp(objc_type, @encode(float)) == 0)
+        result->SetDoubleWithoutPathExpansion(str_key, [value doubleValue]);
+      else
+        result->SetIntegerWithoutPathExpansion(str_key, [value intValue]);
+    } else if ([value isKindOfClass:[NSArray class]]) {
+      scoped_ptr<base::ListValue> sub_arr = NSArrayToListValue(value);
+      if (sub_arr)
+        result->SetWithoutPathExpansion(str_key, std::move(sub_arr));
+      else
+        result->SetWithoutPathExpansion(str_key,
+                                        base::Value::CreateNullValue());
+    } else if ([value isKindOfClass:[NSDictionary class]]) {
+      scoped_ptr<base::DictionaryValue> sub_dict =
+          NSDictionaryToDictionaryValue(value);
+      if (sub_dict)
+        result->SetWithoutPathExpansion(str_key, std::move(sub_dict));
+      else
+        result->SetWithoutPathExpansion(str_key,
+                                        base::Value::CreateNullValue());
+    } else {
+      result->SetStringWithoutPathExpansion(
+          str_key,
+          base::SysNSStringToUTF8([value description]));
+    }
+  }
+
+  return result;
 }
 
 }  // namespace atom

+ 8 - 4
docs/api/system-preferences.md

@@ -13,12 +13,16 @@ This method returns `true` if the system is in Dark Mode, and `false` otherwise.
 * `event` String
 * `callback` Function
 
-Subscribes to native notifications of OS X, `callback` will be called when the
-corresponding `event` happens. The `id` of the subscriber is returned, which can
-be used to unsubscribe the `event`.
+Subscribes to native notifications of OS X, `callback` will be called with
+`callback(event, userInfo)` when the corresponding `event` happens. The
+`userInfo` is an Object that contains the user information dictionary sent
+along with the notification.
+
+The `id` of the subscriber is returned, which can be used to unsubscribe the
+`event`.
 
 Under the hood this API subscribes to `NSDistributedNotificationCenter`,
-possible values of `event` are:
+example values of `event` are:
 
 * `AppleInterfaceThemeChangedNotification`
 * `AppleAquaColorVariantChanged`