Bug 678695 - Settings API. r=sicking, fabrice, smaug
authorGregor Wagner <anygregor@gmail.com>
Mon, 26 Mar 2012 14:49:38 -0700
changeset 93675 b0d644ecd8a72456c23d7ecb28f15b678998550e
parent 93674 2e7a23be3310886bab0f04456161b49fd8bb121a
child 93676 603d27ac23e25037bb28aa4a600d97b1a58ad6da
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking, fabrice, smaug
bugs678695
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 678695 - Settings API. r=sicking, fabrice, smaug
b2g/app/b2g.js
b2g/chrome/content/shell.js
b2g/installer/package-manifest.in
browser/installer/package-manifest.in
content/events/public/nsIPrivateDOMEvent.h
content/events/src/Makefile.in
content/events/src/nsDOMSettingsEvent.cpp
content/events/src/nsDOMSettingsEvent.h
dom/Makefile.in
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/dom-config.mk
dom/interfaces/settings/Makefile.in
dom/interfaces/settings/nsIDOMSettingsManager.idl
dom/settings/Makefile.in
dom/settings/SettingsManager.js
dom/settings/SettingsManager.manifest
dom/settings/tests/Makefile.in
dom/settings/tests/test_settings_basics.html
dom/settings/tests/test_settings_events.html
js/xpconnect/src/dictionary_helper_gen.conf
layout/build/Makefile.in
modules/libpref/src/init/all.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -433,16 +433,19 @@ pref("dom.mozBrowserFramesWhitelist", "h
 // Temporary permission hack for WebSMS
 pref("dom.sms.enabled", true);
 pref("dom.sms.whitelist", "file://,http://homescreen.gaiamobile.org,http://sms.gaiamobile.org");
 
 // Temporary permission hack for WebContacts
 pref("dom.mozContacts.enabled", true);
 pref("dom.mozContacts.whitelist", "http://dialer.gaiamobile.org,http://sms.gaiamobile.org");
 
+// WebSettings
+pref("dom.mozSettings.enabled", true);
+
 // Ignore X-Frame-Options headers.
 pref("b2g.ignoreXFrameOptions", true);
 
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
 // "Preview" landing of bug 710563, which is bogged down in analysis
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -41,16 +41,17 @@ XPCOMUtils.defineLazyServiceGetter(Servi
 
 // FIXME Bug 707625
 // until we have a proper security model, add some rights to
 // the pre-installed web applications
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
     'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app',
+    'websettings-read', 'websettings-readwrite',
     'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification',
     'geolocation'
   ];
   urls.forEach(function(url) {
     url = url.trim();
     dump("XxXxX adding permissions for " + url);
     let uri = Services.io.newURI(url, null, null);
     let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -164,16 +164,17 @@
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_json.xpt
 @BINPATH@/components/dom_power.xpt
 @BINPATH@/components/dom_range.xpt
+@BINPATH@/components/dom_settings.xpt
 @BINPATH@/components/dom_sidebar.xpt
 @BINPATH@/components/dom_sms.xpt
 @BINPATH@/components/dom_storage.xpt
 @BINPATH@/components/dom_stylesheets.xpt
 @BINPATH@/components/dom_threads.xpt
 @BINPATH@/components/dom_traversal.xpt
 @BINPATH@/components/dom_views.xpt
 @BINPATH@/components/dom_xbl.xpt
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -168,16 +168,17 @@
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_json.xpt
 @BINPATH@/components/dom_power.xpt
 @BINPATH@/components/dom_range.xpt
+@BINPATH@/components/dom_settings.xpt
 @BINPATH@/components/dom_sidebar.xpt
 @BINPATH@/components/dom_sms.xpt
 @BINPATH@/components/dom_storage.xpt
 @BINPATH@/components/dom_stylesheets.xpt
 @BINPATH@/components/dom_traversal.xpt
 @BINPATH@/components/dom_xbl.xpt
 @BINPATH@/components/dom_xpath.xpt
 @BINPATH@/components/dom_xul.xpt
@@ -414,16 +415,18 @@
 #ifdef MOZ_SERVICES_SYNC
 @BINPATH@/components/SyncComponents.manifest
 @BINPATH@/components/Weave.js
 #endif
 @BINPATH@/components/TelemetryPing.js
 @BINPATH@/components/TelemetryPing.manifest
 @BINPATH@/components/messageWakeupService.js
 @BINPATH@/components/messageWakeupService.manifest
+@BINPATH@/components/SettingsManager.js
+@BINPATH@/components/SettingsManager.manifest
 @BINPATH@/components/Webapps.js
 @BINPATH@/components/Webapps.manifest
 
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
 
 ; Modules
 @BINPATH@/modules/*
--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -142,12 +142,14 @@ nsresult
 NS_NewDOMMozTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsMozTouchEvent* aEvent);
 nsresult
 NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsTouchEvent *aEvent);
 nsresult
 NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMSmsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
+NS_NewDOMMozSettingsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
+nsresult
 NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMHashChangeEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 #endif // nsIPrivateDOMEvent_h__
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -89,16 +89,17 @@ CPPSRCS		= \
 		nsDOMMozTouchEvent.cpp \
 		nsDOMEventTargetHelper.cpp \
 		nsDOMScrollAreaEvent.cpp \
 		nsDOMTransitionEvent.cpp \
 		nsDOMAnimationEvent.cpp \
 		nsDOMPopStateEvent.cpp \
 		nsDOMHashChangeEvent.cpp \
 		nsDOMCloseEvent.cpp \
+		nsDOMSettingsEvent.cpp \
 		nsDOMTouchEvent.cpp \
 		nsDOMCustomEvent.cpp \
 		nsDOMCompositionEvent.cpp \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
@@ -108,16 +109,17 @@ include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES	+= \
              -I$(srcdir)/../../base/src \
              -I$(srcdir)/../../html/content/src \
              -I$(srcdir)/../../html/base/src \
              -I$(srcdir)/../../xul/content/src \
              -I$(srcdir)/../../xml/content/src \
              -I$(srcdir)/../../../dom/base \
+             -I$(srcdir)/../../../dom/settings \
              -I$(srcdir)/../../../dom/src/storage \
              -I$(srcdir)/../../../layout/generic \
              -I$(srcdir)/../../../layout/xul/base/src \
              -I$(srcdir)/../../../layout/xul/base/src/tree/src \
              $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMSettingsEvent.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDOMSettingsEvent.h"
+#include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozSettingsEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSettingValue)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSettingValue)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+DOMCI_DATA(MozSettingsEvent, nsDOMMozSettingsEvent)
+
+NS_INTERFACE_MAP_BEGIN(nsDOMMozSettingsEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozSettingsEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSettingsEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
+
+NS_IMETHODIMP
+nsDOMMozSettingsEvent::GetSettingName(nsAString & aSettingName)
+{
+  aSettingName = mSettingName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMozSettingsEvent::GetSettingValue(nsIVariant** aSettingValue)
+{
+  NS_IF_ADDREF(*aSettingValue = mSettingValue);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMozSettingsEvent::InitMozSettingsEvent(const nsAString& aType,
+                                            bool aCanBubble,
+                                            bool aCancelable,
+                                            const nsAString &aSettingName,
+                                            nsIVariant *aSettingValue)
+{
+  nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mSettingName = aSettingName;
+  mSettingValue = aSettingValue;
+
+  return NS_OK;
+}
+
+nsresult
+nsDOMMozSettingsEvent::InitFromCtor(const nsAString& aType,
+                                    JSContext* aCx, jsval* aVal)
+{
+  mozilla::dom::MozSettingsEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitMozSettingsEvent(aType, d.bubbles, d.cancelable, d.settingName, d.settingValue);
+}
+
+nsresult
+NS_NewDOMMozSettingsEvent(nsIDOMEvent** aInstancePtrResult,
+                          nsPresContext* aPresContext,
+                          nsEvent* aEvent) 
+{
+  nsDOMMozSettingsEvent* e = new nsDOMMozSettingsEvent(aPresContext, aEvent);
+  return CallQueryInterface(e, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMSettingsEvent.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsDOMSettingsEvent_h__
+#define nsDOMSettingsEvent_h__
+
+#include "nsIDOMSettingsManager.h"
+#include "nsDOMEvent.h"
+
+class nsDOMMozSettingsEvent : public nsDOMEvent,
+                              public nsIDOMMozSettingsEvent
+{
+public:
+  nsDOMMozSettingsEvent(nsPresContext* aPresContext, nsEvent* aEvent)
+    : nsDOMEvent(aPresContext, aEvent) {}
+                     
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
+  // Forward to base class
+  NS_FORWARD_TO_NSDOMEVENT
+
+  NS_DECL_NSIDOMMOZSETTINGSEVENT
+
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
+private:
+  nsString mSettingName;
+  nsCOMPtr<nsIVariant> mSettingValue;
+};
+
+#endif // nsDOMSettingsEvent_h__
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -46,16 +46,17 @@ MODULE		= dom
 
 DIRS = \
   interfaces/base \
   interfaces/canvas \
   interfaces/contacts \
   interfaces/core \
   interfaces/html \
   interfaces/events \
+  interfaces/settings \
   interfaces/stylesheets \
   interfaces/sidebar \
   interfaces/css \
   interfaces/traversal \
   interfaces/range \
   interfaces/xbl \
   interfaces/xpath \
   interfaces/load-save \
@@ -73,16 +74,17 @@ DIRS += \
   interfaces/apps \
   $(NULL)
 
 DIRS += \
   base \
   battery \
   contacts \
   power \
+  settings \
   sms \
   src \
   locales \
   network \
   plugins/base \
   plugins/ipc \
   indexedDB \
   system \
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -203,16 +203,17 @@
 
 #include "nsIDOMLSProgressEvent.h"
 #include "nsIDOMParser.h"
 #include "nsIDOMSerializer.h"
 #include "nsXMLHttpRequest.h"
 #include "nsWebSocket.h"
 #include "nsIDOMCloseEvent.h"
 #include "nsEventSource.h"
+#include "nsIDOMSettingsManager.h"
 
 // includes needed for the prototype chain interfaces
 #include "nsIDOMNavigator.h"
 #include "nsIDOMBarProp.h"
 #include "nsIDOMScreen.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMDOMImplementation.h"
 #include "nsIDOMDocumentFragment.h"
@@ -1612,16 +1613,19 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MediaQueryList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CustomEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
+  NS_DEFINE_CLASSINFO_DATA(MozSettingsEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
 #ifdef MOZ_B2G_RIL
   NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TelephonyCall, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
@@ -1675,16 +1679,17 @@ static const nsContractIDMapData kConstr
   }
 
 NS_DEFINE_EVENT_CTOR(Event)
 NS_DEFINE_EVENT_CTOR(CustomEvent)
 NS_DEFINE_EVENT_CTOR(PopStateEvent)
 NS_DEFINE_EVENT_CTOR(HashChangeEvent)
 NS_DEFINE_EVENT_CTOR(PageTransitionEvent)
 NS_DEFINE_EVENT_CTOR(CloseEvent)
+NS_DEFINE_EVENT_CTOR(MozSettingsEvent)
 NS_DEFINE_EVENT_CTOR(UIEvent)
 NS_DEFINE_EVENT_CTOR(MouseEvent)
 nsresult
 NS_DOMStorageEventCtor(nsISupports** aInstancePtrResult)
 {
   nsDOMStorageEvent* e = new nsDOMStorageEvent();
   return CallQueryInterface(e, aInstancePtrResult);
 }
@@ -1707,16 +1712,17 @@ static const nsConstructorFuncMapData kC
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CustomEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PopStateEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(HashChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PageTransitionEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CloseEvent)
+  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozSettingsEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
 };
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nsnull;
 nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nsnull;
@@ -4359,16 +4365,21 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMediaQueryList)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CustomEvent, nsIDOMCustomEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCustomEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(MozSettingsEvent, nsIDOMMozSettingsEvent)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSettingsEvent)
+     DOM_CLASSINFO_EVENT_MAP_ENTRIES
+   DOM_CLASSINFO_MAP_END
+
 #ifdef MOZ_B2G_RIL
   DOM_CLASSINFO_MAP_BEGIN(Telephony, nsIDOMTelephony)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTelephony)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(TelephonyCall, nsIDOMTelephonyCall)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTelephonyCall)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -527,16 +527,17 @@ DOMCI_CLASS(Touch)
 DOMCI_CLASS(TouchList)
 DOMCI_CLASS(TouchEvent)
 
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(MediaQueryList)
 DOMCI_CLASS(CustomEvent)
+DOMCI_CLASS(MozSettingsEvent)
 
 #ifdef MOZ_B2G_RIL
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 #endif
 
 #ifdef MOZ_B2G_BT
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -1,13 +1,14 @@
 DOM_SRCDIRS = \
   dom/base \
   dom/battery \
   dom/power \
   dom/network/src \
+  dom/settings \
   dom/sms/src \
   dom/contacts \
   dom/src/events \
   dom/src/storage \
   dom/src/offline \
   dom/src/geolocation \
   dom/src/notification \
   dom/workers \
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/settings/Makefile.in
@@ -0,0 +1,20 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE         = dom
+XPIDL_MODULE   = dom_settings
+GRE_MODULE     = 1
+
+XPIDLSRCS =                           \
+            nsIDOMSettingsManager.idl \
+            $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/settings/nsIDOMSettingsManager.idl
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "domstubs.idl"
+#include "nsIDOMEventTarget.idl"
+#include "nsIDOMEvent.idl"
+
+interface nsIDOMDOMRequest;
+interface nsIVariant;
+
+[scriptable, uuid(ef95ddd0-6308-11e1-b86c-0800200c9a66)]
+interface nsIDOMSettingsLock : nsISupports
+{
+  // Contains a JSON object with name/value pairs to be set.
+  nsIDOMDOMRequest set(in nsIVariant settings);
+
+  // result contains the value of the setting.
+  nsIDOMDOMRequest get(in jsval name);
+
+  nsIDOMDOMRequest clear();
+};
+
+[scriptable, uuid(5609d0a0-52a9-11e1-b86c-0800200c9a66)]
+interface nsIDOMSettingsManager : nsISupports
+{
+  nsIDOMSettingsLock getLock();
+
+  attribute nsIDOMEventListener onsettingchange;
+};
+
+[scriptable, uuid(5ce02690-52a9-11e1-b86c-0800200c9a66)]
+interface nsIDOMMozSettingsEvent : nsIDOMEvent
+{
+  readonly attribute DOMString  settingName;
+  readonly attribute nsIVariant settingValue;
+
+  [noscript] void initMozSettingsEvent(in DOMString aType,
+                                       in boolean aCanBubble,
+                                       in boolean aCancelable,
+                                       in DOMString aSettingName,
+                                       in nsIVariant aSettingValue);
+};
+
+dictionary MozSettingsEventInit : EventInit
+{
+  DOMString  settingName;
+  nsIVariant settingValue;
+};
new file mode 100644
--- /dev/null
+++ b/dom/settings/Makefile.in
@@ -0,0 +1,35 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH            = \
+  $(srcdir)        \
+  $(NULL)
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE         = dom
+LIBRARY_NAME   = jsdomsettings_s
+LIBXUL_LIBRARY = 1
+
+EXTRA_COMPONENTS =         \
+  SettingsManager.js       \
+  SettingsManager.manifest \
+  $(NULL)
+
+ifdef ENABLE_TESTS
+DIRS += tests
+endif
+
+# Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
+# subdirectory (and the ipc one).
+# LOCAL_INCLUDES += $(VPATH:%=-I%)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -D_IMPL_NS_LAYOUT
new file mode 100644
--- /dev/null
+++ b/dom/settings/SettingsManager.js
@@ -0,0 +1,361 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict"
+
+/* static functions */
+let DEBUG = 0;
+if (DEBUG)
+  debug = function (s) { dump("-*- SettingsManager: " + s + "\n"); }
+else
+  debug = function (s) {}
+
+function Queue() {
+  this._queue = [];
+  this._index = 0;
+}
+
+Queue.prototype = {
+  getLength: function() { return (this._queue.length - this._index); },
+
+  isEmpty: function() { return (this._queue.length == 0); },
+
+  enqueue: function(item) { this._queue.push(item); },
+
+  dequeue: function() {
+    if(this.isEmpty())
+      return undefined;
+
+    var item = this._queue[this._index];
+    if (++this._index * 2 >= this._queue.length){
+      this._queue  = this._queue.slice(this._index);
+      this._index = 0;
+    }
+    return item;
+  }
+}
+
+const DB_NAME = "settings";
+const DB_VERSION = 1;
+const STORE_NAME = "settings";
+
+function SettingsDB() {}
+
+SettingsDB.prototype = {
+
+  db: null,
+
+  close: function close() {
+    if (this.db)
+      this.db.close();
+  },
+
+  /**
+   * Prepare the database. This may include opening the database and upgrading
+   * it to the latest schema version.
+   * 
+   * @return (via callback) a database ready for use.
+   */
+  ensureDB: function ensureDB(aSuccessCb, aFailureCb, aGlobal) {
+    if (this.db) {
+      debug("ensureDB: already have a database, returning early.");
+      return;
+    }
+
+    let self = this;
+    debug("try to open database:" + DB_NAME + " " + DB_VERSION + " " + this._indexedDB);
+    let req = aGlobal.mozIndexedDB.open(DB_NAME, DB_VERSION);
+    req.onsuccess = function (event) {
+      debug("Opened database:", DB_NAME, DB_VERSION);
+      self.db = event.target.result;
+      self.db.onversionchange = function(event) {
+        debug("WARNING: DB modified from a different window.");
+      }
+      aSuccessCb();
+    };
+    req.onupgradeneeded = function (aEvent) {
+      debug("Database needs upgrade:" + DB_NAME + aEvent.oldVersion + aEvent.newVersion);
+      debug("Correct new database version:" + aEvent.newVersion == DB_VERSION);
+
+      let db = aEvent.target.result;
+      switch (aEvent.oldVersion) {
+        case 0:
+          debug("New database");
+          self.createSchema(db);
+          break;
+
+        default:
+          debug("No idea what to do with old database version:" + aEvent.oldVersion);
+          aFailureCb(aEvent.target.errorMessage);
+          break;
+      }
+    };
+    req.onerror = function (aEvent) {
+      debug("Failed to open database:", DB_NAME);
+      aFailureCb(aEvent.target.errorMessage);
+    };
+    req.onblocked = function (aEvent) {
+      debug("Opening database request is blocked.");
+    };
+  },
+
+  createSchema: function createSchema(aDb) {
+    let objectStore = aDb.createObjectStore(STORE_NAME, {keyPath: "settingName"});
+    objectStore.createIndex("settingValue", "settingValue", { unique: false });
+    debug("Created object stores and indexes");
+  }
+}
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
+  return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
+});
+
+const nsIClassInfo            = Ci.nsIClassInfo;
+const SETTINGSLOCK_CONTRACTID = "@mozilla.org/settingsLock;1";
+const SETTINGSLOCK_CID        = Components.ID("{ef95ddd0-6308-11e1-b86c-0800200c9a66}");
+const nsIDOMSettingsLock      = Ci.nsIDOMSettingsLock;
+
+function SettingsLock(aSettingsManager)
+{
+  this._open = true;
+  this._requests = new Queue();
+  this._settingsManager = aSettingsManager;
+  this._transaction = null;
+}
+
+SettingsLock.prototype = {
+
+  process: function process() {
+    let lock = this;
+    lock._open = false;
+    let store = lock._transaction.objectStore(STORE_NAME);
+
+    while (!lock._requests.isEmpty()) {
+      let info = lock._requests.dequeue();
+      debug("info:" + info.intent);
+      let request = info.request;
+      switch (info.intent) {
+        case "clear":
+          let req = store.clear();
+          req.onsuccess = function() { this._open = true;
+                                       Services.DOMRequest.fireSuccess(request, 0);
+                                       this._open = false; }.bind(lock);
+          req.onerror = function() { Services.DOMRequest.fireError(request, 0) };
+          break;
+        case "set":
+          for (var key in info.settings) {
+            debug("key: " + key + ", val: " + JSON.stringify(info.settings[key]) + "type: " + typeof(info.settings[key]));
+
+            if(typeof(info.settings[key]) != 'object') {
+              req = store.put({settingName: key, settingValue: info.settings[key]});
+            } else {
+              //Workaround for cloning issues
+              let obj = JSON.parse(JSON.stringify(info.settings[key]));
+              req = store.put({settingName: key, settingValue: obj});
+            }
+            req.onsuccess = function() { this._open = true;
+                                         if (this._settingsManager._onsettingchange) {
+                                           let event = new this._settingsManager._window.MozSettingsEvent("settingchanged", {settingName: key, settingValue: info.settings[key]});
+                                           this._settingsManager._onsettingchange.handleEvent(event);
+                                         }
+                                         Services.obs.notifyObservers(this, "mozsettings-changed-"+key, JSON.stringify(info.settings[key]));
+                                         Services.DOMRequest.fireSuccess(request, 0);
+                                         this._open = false; }.bind(lock);
+            req.onerror = function() { Services.DOMRequest.fireError(request, 0) };
+          }
+          break;
+        case "get":
+          if (info.name == "*") {
+            req = store.getAll();
+          } else {
+            req = store.getAll(info.name);
+          }
+          req.onsuccess = function(event) {
+            debug("Request successful. Record count:" + event.target.result.length);
+            debug("result: " + JSON.stringify(event.target.result));
+            var result = {};
+            for (var i in event.target.result)
+              result[event.target.result[i].settingName] = event.target.result[i].settingValue;
+            this._open = true;
+            Services.DOMRequest.fireSuccess(request, result);
+            this._open = false;
+          }.bind(lock);
+          req.onerror = function() { Services.DOMRequest.fireError(request, 0)};
+          break;
+      }
+    }
+    if (!lock._requests.isEmpty())
+      throw Components.results.NS_ERROR_ABORT;
+    lock._open = true;
+  },
+
+  createTransactionAndProcess: function() {
+    if (this._settingsManager._settingsDB.db) {
+      var lock;
+      while (lock = this._settingsManager._locks.dequeue()) {
+        if (!lock._transaction) {
+          lock._transaction = lock._settingsManager._settingsDB.db.transaction(STORE_NAME, "readwrite");
+        }
+        lock.process();
+      }
+      if (!this._requests.isEmpty())
+        this.process();
+    }
+  },
+
+  get: function get(aName) {
+    if (!this._open)
+      throw Components.results.NS_ERROR_ABORT;
+
+    if (this._settingsManager.hasReadPrivileges || this._settingsManager.hasReadWritePrivileges) {
+      let req = Services.DOMRequest.createRequest(this._settingsManager._window);
+      this._requests.enqueue({ request: req, intent:"get", name: aName });
+      this.createTransactionAndProcess();
+      return req;
+    } else {
+      debug("get not allowed");
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  set: function set(aSettings) {
+    if (!this._open)
+      throw Components.results.NS_ERROR_ABORT;
+
+    if (this._settingsManager.hasReadWritePrivileges) {
+      let req = Services.DOMRequest.createRequest(this._settingsManager._window);
+      debug("send: " + JSON.stringify(aSettings));
+      this._requests.enqueue({request: req, intent: "set", settings: aSettings});
+      this.createTransactionAndProcess();
+      return req;
+    } else {
+      debug("set not allowed");
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  clear: function clear() {
+    if (!this._open)
+      throw Components.results.NS_ERROR_ABORT;
+
+    if (this._settingsManager.hasReadWritePrivileges) {
+      let req = Services.DOMRequest.createRequest(this._settingsManager._window);
+      this._requests.enqueue({ request: req, intent: "clear"});
+      this.createTransactionAndProcess();
+      return req;
+    } else {
+      debug("clear not allowed");
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  classID : SETTINGSLOCK_CID,
+  QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsLock]),
+
+  classInfo : XPCOMUtils.generateCI({classID: SETTINGSLOCK_CID,
+                                     contractID: SETTINGSLOCK_CONTRACTID,
+                                     classDescription: "SettingsLock",
+                                     interfaces: [nsIDOMSettingsLock],
+                                     flags: nsIClassInfo.DOM_OBJECT})
+};
+
+const SETTINGSMANAGER_CONTRACTID = "@mozilla.org/settingsManager;1";
+const SETTINGSMANAGER_CID        = Components.ID("{5609d0a0-52a9-11e1-b86c-0800200c9a66}");
+const nsIDOMSettingsManager      = Ci.nsIDOMSettingsManager;
+
+let myGlobal = this;
+
+function SettingsManager()
+{
+  this._locks = new Queue();
+  var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
+  idbManager.initWindowless(myGlobal);
+  this._settingsDB = new SettingsDB();
+}
+
+SettingsManager.prototype = {
+  _onsettingchange: null,
+
+  nextTick: function nextTick(aCallback, thisObj) {
+    if (thisObj)
+      aCallback = aCallback.bind(thisObj);
+
+    Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
+  },
+
+  set onsettingchange(aCallback) {
+    if (this.hasReadPrivileges || this.hasReadWritePrivileges)
+      this._onsettingchange = aCallback;
+    else
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+  },
+
+  get onsettingchange() {
+    return this._onsettingchange;
+  },
+
+  getLock: function() {
+    debug("get lock!");
+    var lock = new SettingsLock(this);
+    this._locks.enqueue(lock);
+    this._settingsDB.ensureDB(
+      function() { lock.createTransactionAndProcess(); },
+      function() { dump("ensureDB error cb!\n"); },
+      myGlobal );
+    this.nextTick(function() { this._open = false; }, lock);
+    return lock;
+  },
+
+  init: function(aWindow) {
+    // Set navigator.mozSettings to null.
+    if (!Services.prefs.getBoolPref("dom.mozSettings.enabled"))
+      return null;
+
+    this._window = aWindow;
+    Services.obs.addObserver(this, "inner-window-destroyed", false);
+    let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    this.innerWindowID = util.currentInnerWindowID;
+
+    let principal = aWindow.document.nodePrincipal;
+    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
+    let readPerm = principal == secMan.getSystemPrincipal() ? Ci.nsIPermissionManager.ALLOW_ACTION : Services.perms.testExactPermission(principal.URI, "websettings-read");
+    let readwritePerm = principal == secMan.getSystemPrincipal() ? Ci.nsIPermissionManager.ALLOW_ACTION : Services.perms.testExactPermission(principal.URI, "websettings-readwrite");
+    this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
+    this.hasReadWritePrivileges = readwritePerm == Ci.nsIPermissionManager.ALLOW_ACTION;
+    debug("has read privileges :" + this.hasReadPrivileges + ", has read-write privileges: " + this.hasReadWritePrivileges);
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    debug("Topic: " + aTopic);
+    if (aTopic == "inner-window-destroyed") {
+      let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
+      if (wId == this.innerWindowID) {
+        Services.obs.removeObserver(this, "inner-window-destroyed");
+        this._requests = null;
+        this._window = null;
+        this._innerWindowID = null;
+        this._onsettingchange = null;
+        this._settingsDB.close();
+      }
+    }
+  },
+
+  classID : SETTINGSMANAGER_CID,
+  QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsManager, Ci.nsIDOMGlobalPropertyInitializer]),
+
+  classInfo : XPCOMUtils.generateCI({classID: SETTINGSMANAGER_CID,
+                                     contractID: SETTINGSMANAGER_CONTRACTID,
+                                     classDescription: "SettingsManager",
+                                     interfaces: [nsIDOMSettingsManager],
+                                     flags: nsIClassInfo.DOM_OBJECT})
+}
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock])
new file mode 100644
--- /dev/null
+++ b/dom/settings/SettingsManager.manifest
@@ -0,0 +1,6 @@
+component {5609d0a0-52a9-11e1-b86c-0800200c9a66} SettingsManager.js
+contract @mozilla.org/settingsManager;1 {5609d0a0-52a9-11e1-b86c-0800200c9a66}
+category JavaScript-navigator-property mozSettings @mozilla.org/settingsManager;1
+
+component {ef95ddd0-6308-11e1-b86c-0800200c9a66} SettingsManager.js
+contract @mozilla.org/settingsLock;1 {ef95ddd0-6308-11e1-b86c-0800200c9a66}
new file mode 100644
--- /dev/null
+++ b/dom/settings/tests/Makefile.in
@@ -0,0 +1,28 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH            = ../../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+relativesrcdir   = dom/settings/tests
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = \
+  test_settings_basics.html \
+  test_settings_events.html \
+  $(NULL)
+
+_CHROME_TEST_FILES = \
+  $(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/settings/tests/test_settings_basics.html
@@ -0,0 +1,526 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id={678695}
+-->
+<head>
+  <title>Test for Bug {678695} Settings API</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={678695}">Mozilla Bug {678695}</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+"use strict"
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+Components.classes["@mozilla.org/permissionmanager;1"]
+          .getService(Components.interfaces.nsIPermissionManager)
+          .add(SpecialPowers.getDocumentURIObject(window.document),
+               "websettings-read",
+               Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
+Components.classes["@mozilla.org/permissionmanager;1"]
+          .getService(Components.interfaces.nsIPermissionManager)
+          .add(SpecialPowers.getDocumentURIObject(window.document),
+               "websettings-readwrite",
+               Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
+
+function onUnwantedSuccess() {
+  ok(false, "onUnwantedSuccess: shouldn't get here");
+}
+
+function onFailure() {
+  ok(false, "in on Failure!");
+}
+
+var wifi  = {"net3g.apn": "internet.mnc012.mcc345.gprs"};
+var wifi2 = {"net3g.apn": "internet.mnc012.mcc345.test"};
+var wifiEnabled = {"wifi.enabled": true};
+var wifiDisabled = {"wifi.enabled": false};
+var screenBright = {"screen.brightness": 0.7};
+var wifiNetworks0 = { "wifi.networks[0]": { ssid: "myfreenetwork", mac: "01:23:45:67:89:ab", passwd: "secret"}};
+var wifiNetworks1 = { "wifi.networks[1]": { ssid: "myfreenetwork2", mac: "01:23:45:67:89:ab", passwd: "secret2"}};
+
+function equals(o1, o2) {
+  var k1 = Object.keys(o1).sort();
+  var k2 = Object.keys(o2).sort();
+  if (k1.length != k2.length) return false;
+  return k1.zip(k2, function(keyPair) {
+    if(typeof o1[keyPair[0]] == typeof o2[keyPair[1]] == "object"){
+      return equals(o1[keyPair[0]], o2[keyPair[1]])
+    } else {
+      return o1[keyPair[0]] == o2[keyPair[1]];
+    }
+  }).all();
+};
+
+function check(o1, o2) {
+  is(JSON.stringify(o1), JSON.stringify(o2), "same");
+}
+
+var req, req2, req3, req4, req5, req6;
+var index = 0;
+
+var mozSettings = window.navigator.mozSettings;
+
+var steps = [
+  function () {
+    ok(true, "Deleting database");
+    var lock = mozSettings.getLock();
+    req = lock.clear();
+    req.onsuccess = function () {
+      ok(true, "Deleted the database");
+    };
+    req.onerror = onFailure;
+    req2 = lock.set(screenBright);
+    req2.onsuccess = function () {
+      ok(true, "set done");
+      next();
+    }
+    req2.onerror = onFailure;
+  },
+  function() {
+    ok(true, "adding Event Listener2");
+    navigator.mozSettings.onsettingchange = function(event) {
+      is(event.settingName, "screen.brightness", "Same settingName");
+      is(event.settingValue, "0.7", "Same settingvalue");
+    }
+    var lock = mozSettings.getLock();
+    req2 = lock.get("screen.brightness");
+    req2.onsuccess = function() {
+      next();
+    };
+    req2.onerror = onFailure;
+  },
+  function() {
+    ok(true, "adding Event Listener");
+    var lock = mozSettings.getLock();
+    req = lock.set(screenBright);
+    req.onsuccess = function () {
+      ok(true, "set done");
+      navigator.mozSettings.onsettingchange = null;
+      next();
+    }
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Nested test");
+    var lock = mozSettings.getLock();
+    req = lock.get("screen.brightness");
+    req.onsuccess = function () {
+      req3 = lock.set({"screen.brightness": req.result["screen.brightness"] + 1})
+      req3.onsuccess = function () {
+        req4 = lock.get("screen.brightness");
+        req4.onsuccess = function() {
+          is(req4.result["screen.brightness"], 1.7, "same Value");
+        }
+        req4.onerror = onFailure;
+      }
+      req3.onerror = onFailure;
+    };
+    req.onerror = onFailure;
+
+    req2 = lock.get("screen.brightness");
+    req2.onsuccess = function () {
+      is(req2.result["screen.brightness"], 0.7, "same Value");
+    }
+    req2.onerror = onFailure;
+    
+    var lock2 = mozSettings.getLock();
+    req5 = lock2.get("screen.brightness");
+    req5.onsuccess = function () {
+      is(req5.result["screen.brightness"], 1.7, "same Value");
+      next();
+    }
+    req5.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Deleting database");
+    var lock = mozSettings.getLock();
+    req = lock.clear();
+    req.onsuccess = function () {
+      ok(true, "Deleted the database");
+    };
+    req.onerror = onFailure;
+    req2 = lock.set(wifi);
+    req2.onsuccess = function () {
+      ok(true, "set done");
+    }
+    req2.onerror = onFailure;
+
+    ok(true, "Get all settings");
+    var lock2 = mozSettings.getLock();
+    req = lock2.get("*");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 1, "length 1");
+      check(wifi, req.result);
+      ok(true, JSON.stringify(req.result));
+      ok(true, "Get all settings Done");
+    };
+    req.onerror = onFailure;
+
+    req2 = lock2.get("net3g.apn");
+    req2.onsuccess = function () {
+      is(Object.keys(req2.result).length, 1, "length 1");
+      check(wifi, req2.result);
+      ok(true, "Get net3g.apn Done");
+      next();
+    };
+    req2.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Change wifi");
+    var lock = mozSettings.getLock();
+    req = lock.set(wifi2);
+    req.onsuccess = function () {
+      ok(true, "Set Done");
+    };
+    req.onerror = onFailure;
+
+    ok(true, "Get changed net3g.apn");
+    req2 = lock.get("net3g.apn");
+    req2.onsuccess = function () {
+      is(Object.keys(req2.result).length, 1, "length 1");
+      check(wifi2, req2.result);
+      ok(true, "Get net3g.apn Done");
+      next();
+    };
+    req2.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Test locking");
+    var lock = mozSettings.getLock();
+    var lock2 = mozSettings.getLock();
+    req = lock.set(wifiEnabled);
+    req.onsuccess = function () {
+      ok(true, "Test Locking Done");
+    };
+    req.onerror = onFailure;
+
+    req2 = lock2.set(wifiDisabled);
+    req2.onsuccess = function () {
+      ok(true, "Set Done");
+      next();
+    };
+    req2.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Test locking result");
+    var lock = mozSettings.getLock();
+    req = lock.get("wifi.enabled");
+    req.onsuccess = function() {
+      check(req.result, wifiDisabled);
+      ok(true, "Test1 locking result done");
+      next();
+    }
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Test locking heavy");
+    for (var i=0; i<30; i++) {
+      // only new locks!
+      var lock = mozSettings.getLock();
+      var obj = {};
+      obj["wifi.enabled" + i] = true;
+      req = lock.set( obj );
+      req.onsuccess = function () {
+        ok(true, "Set1 Done");
+      };
+      req.onerror = onFailure;
+    };
+    {
+      var lock2 = mozSettings.getLock();
+      req = lock2.get("*");
+      req.onsuccess = function () {
+        is(Object.keys(req.result).length, 32, "length 12");
+        ok(true, JSON.stringify(req.result));
+        ok(true, "Get all settings Done");
+      };
+      req.onerror = onFailure;
+    }
+    var lock2 = mozSettings.getLock();
+    var obj = {};
+    obj["wifi.enabled" + 30] = true;
+    req2 = lock2.set( obj );
+    req2.onsuccess = function () {
+      ok(true, "Set12 Done");
+    };
+    req2.onerror = onFailure;
+
+    var lock3 = mozSettings.getLock();
+    // with one lock
+    for (var i = 0; i < 30; i++) {
+      req3 = lock3.get("wifi.enabled" + i);
+      var testObj = {};
+      testObj["wifi.enabled" + i] = true;
+      req3.onsuccess = function () {
+        check(this.request.result, this.testObj);
+        ok(true, "Get1 Done");
+      }.bind({testObj: testObj, request: req3});
+      req3.onerror = onFailure;
+    }
+
+    ok(true, "start next2!");
+    var lock4 = mozSettings.getLock();
+    for (var i=0; i<30; i++) {
+      var obj = {};
+      obj["wifi.enabled" + i] = false;
+      req4 = lock4.set( obj );
+      req4.onsuccess = function () {
+        ok(true, "Set2 Done");
+      };
+      req4.onerror = onFailure;
+    }
+    var lock5 = mozSettings.getLock();
+    for (var i=0; i<30; i++) {
+      req5 = lock5.get("wifi.enabled" + i);
+      var testObj = {};
+      testObj["wifi.enabled" + i] = false;
+      req5.onsuccess = function () {
+        check(this.request.result, this.testObj);
+        ok(true, "Get2 Done");
+      }.bind({testObj: testObj, request: req5});
+      req5.onerror = onFailure;
+    }
+    
+    var lock5 = mozSettings.getLock();
+    req6 = lock5.clear();
+    req6.onsuccess = function () {
+      ok(true, "Deleted the database");
+      next();
+    };
+    req6.onerror = onFailure;
+  },
+  function () {
+    ok(true, "reverse Test locking");
+    var lock2 = mozSettings.getLock();
+    var lock = mozSettings.getLock();
+
+    req = lock.set(wifiEnabled);
+    req.onsuccess = function () {
+      ok(true, "Test Locking Done");
+      next();
+    };
+    req.onerror = onFailure;
+
+    req2 = lock2.set(wifiDisabled);
+    req2.onsuccess = function () {
+      ok(true, "Set Done");
+    };
+    req2.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Test locking result");
+    var lock = mozSettings.getLock();
+    
+    req = lock.get("wifi.enabled");
+    req.onsuccess = function() {
+      check(req.result, wifiEnabled);
+      ok(true, "Test2 locking result done");
+    }
+    req.onerror = onFailure;
+    
+    req2 = lock.clear();
+    req2.onsuccess = function () {
+      ok(true, "Deleted the database");
+    };
+    req2.onerror = onFailure;
+
+    req3 = lock.set(wifi);
+    req3.onsuccess = function () {
+      ok(true, "set done");
+      next();
+    }
+    req3.onerror = onFailure;
+    
+  },
+  function () {
+    ok(true, "Get all settings");
+    var lock = mozSettings.getLock();
+    req = lock.get("*");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 1, "length 1");
+      check(wifi, req.result);
+      ok(true, "Get all settings Done");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Get net3g.apn");
+    var lock = mozSettings.getLock();
+    req = lock.get("net3g.apn");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 1, "length 1");
+      check(wifi, req.result);
+      ok(true, "Get net3g.apn Done");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Change wifi");
+    var lock = mozSettings.getLock();
+    req = lock.set(wifi2);
+    req.onsuccess = function () {
+      ok(true, "Set Done");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Get net3g.apn");
+    var lock = mozSettings.getLock();
+    req = lock.get("net3g.apn");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 1, "length 1");
+      check(wifi2, req.result);
+      ok(true, "Get net3g.apn Done");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Add wifi.enabled");
+    var lock = mozSettings.getLock();
+    req = lock.set(wifiEnabled);
+    req.onsuccess = function () {
+      ok(true, "Set Done");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Get Wifi Enabled");
+    var lock = mozSettings.getLock();
+    req = lock.get("wifi.enabled");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 1, "length 1");
+      check(wifiEnabled, req.result);
+      ok(true, "Get wifi.enabledDone");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Get all");
+    var lock = mozSettings.getLock();
+    req = lock.get("*");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 2, "length 2");
+      check(wifiEnabled["wifi.enabled"], req.result["wifi.enabled"]);
+      check(wifi2["net3g.apn"], req.result["net3g.apn"]);
+      ok(true, "Get all Done");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Add wifiNetworks");
+    var lock = mozSettings.getLock();
+    req = lock.set(wifiNetworks0);
+    req.onsuccess = function () {
+      ok(true, "Set Done");
+    };
+    req.onerror = onFailure;
+
+    req2 = lock.set(wifiNetworks1);
+    req2.onsuccess = function () {
+      ok(true, "Set Done");
+      next();
+    };
+    req2.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Get Wifi Networks");
+    var lock = mozSettings.getLock();
+    req = lock.get("wifi.networks[0]");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 1, "length 1");
+      check(wifiNetworks0, req.result);
+      ok(true, "Get wifi.networks[0]");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    ok(true, "Clear DB, multiple locks");
+    var lock4 = mozSettings.getLock();
+    var lock3 = mozSettings.getLock();
+    var lock2 = mozSettings.getLock();
+    var lock = mozSettings.getLock();
+    var lock6 = mozSettings.getLock();
+    var lock7 = mozSettings.getLock();
+    req = lock.clear();
+    req.onsuccess = function () {
+      ok(true, "Deleted the database");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Add wifiNetworks");
+    var lock = mozSettings.getLock();
+    req = lock.set(wifiNetworks0);
+    req.onsuccess = function () {
+      ok(true, "Set Done");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    ok(true, "Clear DB");
+    var lock = mozSettings.getLock();
+    req = lock.clear();
+    req.onsuccess = function () {
+      ok(true, "Deleted the database");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "all done!\n");
+    SimpleTest.finish();
+  }
+];
+
+function next() {
+  ok(true, "Begin!");
+  if (index >= steps.length) {
+    ok(false, "Shouldn't get here!");
+    return;
+  }
+  try {
+    steps[index]();
+  } catch(ex) {
+    ok(false, "Caught exception", ex);
+  }
+  index += 1;
+}
+
+function permissionTest() {
+  if (gSettingsEnabled) {
+    next();
+  } else {
+    is(mozSettings, null, "mozSettings is null when not enabled.");
+    SimpleTest.finish();
+  }
+}
+
+var gSettingsEnabled = SpecialPowers.getBoolPref("dom.mozSettings.enabled");
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(permissionTest);
+
+ok(true, "test passed");
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/settings/tests/test_settings_events.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=678695
+-->
+<head>
+  <title>Test for Bug 678695</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=678695">Mozilla Bug 678695</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 678695 **/
+
+var e = new MozSettingsEvent("settingchanged", {settingName: "a", settingValue: 1});
+ok(e, "Should have settings event!");
+is(e.settingName, "a", "Name should be a.");
+is(e.settingValue, 1, "Value should be 1.");
+
+e = new MozSettingsEvent("settingchanged", {settingName: "test", settingValue: {test: "test"}});
+is(e.settingName, "test", "Name should be 'test'.");
+is(e.settingValue.test, "test", "Name should be 'test'.");
+
+e = new MozSettingsEvent("settingchanged", {settingName: "a", settingValue: true});
+is(e.settingName, "a", "Name should be a.");
+is(e.settingValue, true, "Value should be true.");
+
+
+</script>
+</pre>
+</body>
+</html>
\ No newline at end of file
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -6,17 +6,18 @@ dictionaries = [
      [ 'HashChangeEventInit', 'nsIDOMHashChangeEvent.idl' ],
      [ 'PageTransitionEventInit', 'nsIDOMPageTransitionEvent.idl' ],
      [ 'CloseEventInit', 'nsIDOMCloseEvent.idl' ],
      [ 'UIEventInit', 'nsIDOMUIEvent.idl' ],
      [ 'MouseEventInit', 'nsIDOMMouseEvent.idl' ],
      [ 'IDBObjectStoreParameters', 'nsIIDBDatabase.idl' ],
      [ 'IDBIndexParameters', 'nsIIDBObjectStore.idl' ],
      [ 'StorageEventInit', 'nsIDOMStorageEvent.idl' ],
-     [ 'BlobPropertyBag', 'nsIDOMFile.idl' ]
+     [ 'BlobPropertyBag', 'nsIDOMFile.idl' ],
+     [ 'SettingsEventInit', 'nsIDOMSettingsManager.idl' ]
    ]
 
 # include file names
 special_includes = [
     'nsContentUtils.h',
     'XPCQuickStubs.h'
   ]
 
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -90,16 +90,17 @@ SHARED_LIBRARY_LIBS = \
 	$(DEPTH)/content/xslt/src/xslt/$(LIB_PREFIX)txxslt_s.$(LIB_SUFFIX) \
 	$(DEPTH)/content/xbl/src/$(LIB_PREFIX)gkconxbl_s.$(LIB_SUFFIX) \
 	$(DEPTH)/content/xul/document/src/$(LIB_PREFIX)gkconxuldoc_s.$(LIB_SUFFIX) \
 	$(DEPTH)/view/src/$(LIB_PREFIX)gkview_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/base/$(LIB_PREFIX)jsdombase_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/battery/$(LIB_PREFIX)dom_battery_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/contacts/$(LIB_PREFIX)jsdomcontacts_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \
+	$(DEPTH)/dom/settings/$(LIB_PREFIX)jsdomsettings_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/sms/src/$(LIB_PREFIX)dom_sms_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/json/$(LIB_PREFIX)json_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/jsurl/$(LIB_PREFIX)jsurl_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/storage/$(LIB_PREFIX)jsdomstorage_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/offline/$(LIB_PREFIX)jsdomoffline_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/geolocation/$(LIB_PREFIX)jsdomgeolocation_s.$(LIB_SUFFIX) \
@@ -255,16 +256,17 @@ LOCAL_INCLUDES	+= -I$(srcdir)/../base \
 		   -I$(topsrcdir)/view/src \
 		   -I$(topsrcdir)/dom/base \
 		   -I$(topsrcdir)/dom/src/json \
 		   -I$(topsrcdir)/dom/src/jsurl \
 		   -I$(topsrcdir)/dom/src/storage \
 		   -I$(topsrcdir)/dom/src/offline \
 		   -I$(topsrcdir)/dom/src/geolocation \
 		   -I$(topsrcdir)/dom/contacts \
+		   -I$(topsrcdir)/dom/settings \
 		   -I$(topsrcdir)/dom/telephony \
 		   -I. \
 		   -I$(topsrcdir)/editor/libeditor/base \
 		   -I$(topsrcdir)/editor/libeditor/text \
 		   -I$(topsrcdir)/editor/libeditor/html \
 		   -I$(topsrcdir)/editor/txtsvc/src \
 		   -I$(topsrcdir)/editor/composer/src \
 		   -I$(topsrcdir)/js/xpconnect/src \
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3507,16 +3507,19 @@ pref("dom.battery.enabled", true);
 // WebSMS
 pref("dom.sms.enabled", false);
 pref("dom.sms.whitelist", "");
 
 // WebContacts
 pref("dom.mozContacts.enabled", false);
 pref("dom.mozContacts.whitelist", "");
 
+// WebSettings
+pref("dom.mozSettings.enabled", false);
+
 // enable JS dump() function.
 pref("browser.dom.window.dump.enabled", false);
 
 // SPS Profiler
 pref("profiler.enabled", false);
 pref("profiler.interval", 10);
 pref("profiler.entries", 100000);