Merge mozilla-central and fx-team

This commit is contained in:
Ed Morley 2013-08-07 16:19:09 -07:00
commit f823f7f1ee
15 changed files with 323 additions and 192 deletions

View File

@ -858,15 +858,6 @@
<richlistbox id="menupopup-commands" onclick="if (event.target != this) AutofillMenuUI.selectByIndex(this.selectedIndex);" flex="1"/>
</vbox>
</box>
<!-- alerts for content -->
<hbox id="alerts-container" hidden="true" align="start" bottom="0" onclick="AlertsHelper.click(event);">
<image id="alerts-image"/>
<vbox flex="1">
<label id="alerts-title" value=""/>
<description id="alerts-text" flex="1"/>
</vbox>
</hbox>
</stack>
</window>

View File

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const URI_GENERIC_ICON_DOWNLOAD = "chrome://browser/skin/images/alert-downloads-30.png";
const TOAST_URI_GENERIC_ICON_DOWNLOAD = "ms-appx:///metro/chrome/chrome/skin/images/alert-downloads-30.png"
var Downloads = {
/**
@ -154,26 +155,17 @@ var Downloads = {
BrowserUI.newTab(uri, Browser.selectedTab);
},
showAlert: function dh_showAlert(aName, aMessage, aTitle, aIcon) {
showAlert: function dh_showAlert(aName, aMessage, aTitle, aIcon, aObserver) {
var notifier = Cc["@mozilla.org/alerts-service;1"]
.getService(Ci.nsIAlertsService);
// Callback for tapping on the alert popup
let observer = {
observe: function (aSubject, aTopic, aData) {
if (aTopic == "alertclickcallback") {
// TODO: Bug 783232 turns this alert into a native toast.
}
}
};
if (!aTitle)
aTitle = Strings.browser.GetStringFromName("alertDownloads");
if (!aIcon)
aIcon = URI_GENERIC_ICON_DOWNLOAD;
aIcon = TOAST_URI_GENERIC_ICON_DOWNLOAD;
notifier.showAlertNotification(aIcon, aTitle, aMessage, true, "", observer, aName);
notifier.showAlertNotification(aIcon, aTitle, aMessage, true, "", aObserver, aName);
},
showNotification: function dh_showNotification(title, msg, buttons, priority) {
@ -257,6 +249,53 @@ var Downloads = {
this._notificationBox.PRIORITY_WARNING_MEDIUM);
},
_showDownloadCompleteToast: function (aDownload) {
let name = "DownloadComplete";
let msg = "";
let title = "";
let observer = null;
if (this._downloadCount > 1) {
title = PluralForm.get(this._downloadCount,
Strings.browser.GetStringFromName("alertMultipleDownloadsComplete"))
.replace("#1", this._downloadCount)
msg = PluralForm.get(2, Strings.browser.GetStringFromName("downloadShowInFiles"));
observer = {
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "alertclickcallback":
let fileURI = aDownload.target;
let file = Downloads._getLocalFile(fileURI);
file.reveal();
let downloadCompleteNotification =
Downloads._notificationBox.getNotificationWithValue("download-complete");
Downloads._notificationBox.removeNotification(downloadCompleteNotification);
break;
}
}
}
} else {
title = Strings.browser.formatStringFromName("alertDownloadsDone",
[aDownload.displayName], 1);
msg = Strings.browser.GetStringFromName("downloadRunNow");
observer = {
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "alertclickcallback":
Downloads.openDownload(aDownload);
let downloadCompleteNotification =
Downloads._notificationBox.getNotificationWithValue("download-complete");
Downloads._notificationBox.removeNotification(downloadCompleteNotification);
break;
}
}
}
}
this.showAlert(name, msg, title, null, observer);
},
_updateCircularProgressMeter: function dv_updateCircularProgressMeter() {
if (!this._progressNotificationInfo) {
return;
@ -391,6 +430,7 @@ var Downloads = {
this._runDownloadBooleanMap.delete(download.targetFile.path);
if (this._downloadsInProgress == 0) {
if (this._downloadCount > 1 || !runAfterDownload) {
this._showDownloadCompleteToast(download);
this._showDownloadCompleteNotification(download);
}
this._progressNotificationInfo.clear();

View File

@ -3,80 +3,23 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var AlertsHelper = {
_timeoutID: -1,
_listener: null,
_cookie: "",
_clickable: false,
get container() {
delete this.container;
let container = document.getElementById("alerts-container");
let self = this;
container.addEventListener("transitionend", function() {
self.alertTransitionOver();
}, true);
return this.container = container;
},
showAlertNotification: function ah_show(aImageURL, aTitle, aText, aTextClickable, aCookie, aListener) {
this._clickable = aTextClickable || false;
this._listener = aListener || null;
this._cookie = aCookie || "";
Services.obs.addObserver(this, "metro_native_toast_clicked", false);
this._listener = aListener;
this._cookie = aCookie;
// Reset the container settings from the last time so layout can happen naturally
let container = this.container;
container.removeAttribute("width");
let alertText = document.getElementById("alerts-text");
alertText.style.whiteSpace = "";
document.getElementById("alerts-image").setAttribute("src", aImageURL);
document.getElementById("alerts-title").value = aTitle;
alertText.textContent = aText;
container.hidden = false;
let bcr = container.getBoundingClientRect();
if (bcr.width > window.innerWidth - 50) {
// If the window isn't wide enough, we need to re-layout
container.setAttribute("width", window.innerWidth - 50); // force a max width
alertText.style.whiteSpace = "pre-wrap"; // wrap text as needed
bcr = container.getBoundingClientRect(); // recalculate the bcr
}
container.setAttribute("width", bcr.width); // redundant but cheap
container.setAttribute("height", bcr.height);
container.classList.add("showing");
let timeout = Services.prefs.getIntPref("alerts.totalOpenTime");
let self = this;
if (this._timeoutID)
clearTimeout(this._timeoutID);
this._timeoutID = setTimeout(function() { self._timeoutAlert(); }, timeout);
MetroUtils.showNativeToast(aTitle, aText, aImageURL);
},
_timeoutAlert: function ah__timeoutAlert() {
this._timeoutID = -1;
this.container.classList.remove("showing");
if (this._listener)
this._listener.observe(null, "alertfinished", this._cookie);
},
alertTransitionOver: function ah_alertTransitionOver() {
let container = this.container;
if (!container.classList.contains("showing")) {
container.height = 0;
container.hidden = true;
}
},
click: function ah_click(aEvent) {
if (this._clickable && this._listener)
this._listener.observe(null, "alertclickcallback", this._cookie);
if (this._timeoutID != -1) {
clearTimeout(this._timeoutID);
this._timeoutAlert();
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case "metro_native_toast_clicked":
Services.obs.removeObserver(this, "metro_native_toast_clicked");
this._listener.observe(null, "alertclickcallback", this._cookie);
break;
}
}
};

View File

@ -20,7 +20,28 @@ AlertsService.prototype = {
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName) {
let browser = Services.wm.getMostRecentWindow("navigator:browser");
browser.AlertsHelper.showAlertNotification(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener);
try {
browser.AlertsHelper.showAlertNotification(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener);
} catch (ex) {
let chromeWin = this._getChromeWindow(browser).wrappedJSObject;
let notificationBox = chromeWin.Browser.getNotificationBox();
notificationBox.appendNotification(aTitle,
aText,
aImageUrl,
notificationBox.PRIORITY_WARNING_MEDIUM,
null);
}
},
_getChromeWindow: function (aWindow) {
let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.QueryInterface(Ci.nsIDOMChromeWindow);
return chromeWin;
}
};

View File

@ -61,6 +61,7 @@ downloadRun=Run
downloadSave=Save
downloadCancel=Cancel
downloadTryAgain=Try Again
downloadRunNow=Run it now
# LOCALIZATION NOTE (downloadShowInFiles): 'Files' refers to the Windows 8 file explorer
downloadShowInFiles=Show in Files

View File

@ -1245,37 +1245,4 @@ setting[type="radio"] > vbox {
#clear-notification-done {
font-weight: bold;
}
/* Alert Popup ============================================================= */
#alerts-container {
color: white;
background-color: #5e6166;
border: @border_width_small@ solid #767973;
border-radius: @border_radius_normal@;
box-shadow: black 0 @border_radius_tiny@ @border_radius_tiny@;
padding: @padding_normal@; /* core spacing on top/bottom */
margin-bottom: @margin_large@;
transition-property: opacity;
transition-duration: 0.5s;
opacity: 0;
}
#alerts-container.showing {
opacity: 1;
}
#alerts-title {
font-size: @font_small@ !important;
}
#alerts-text {
font-size: @font_xsmall@ !important;
white-space: pre;
}
#alerts-container {
-moz-margin-end: @margin_large@;
}
}

View File

@ -12,6 +12,6 @@
android:title="@string/pref_developer_remotedebugging" />
<org.mozilla.gecko.AlignRightLinkPreference android:title="@string/pref_developer_remotedebugging_docs"
url="https://developer.mozilla.org/docs/Tools/Debugger#Remote_debugging?" />
url="https://developer.mozilla.org/docs/Tools/Remote_Debugging" />
</PreferenceScreen>

View File

@ -4879,7 +4879,7 @@ var ErrorPageEventHandler = {
let isMalware = errorDoc.documentURI.contains("e=malwareBlocked");
let bucketName = isMalware ? "WARNING_MALWARE_PAGE_" : "WARNING_PHISHING_PAGE_";
let nsISecTel = Ci.nsISecurityUITelemetry;
let isIframe = (aOwnerDoc.defaultView.parent === aOwnerDoc.defaultView);
let isIframe = (errorDoc.defaultView.parent === errorDoc.defaultView);
bucketName += isIframe ? "TOP_" : "FRAME_";
let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);

View File

@ -424,8 +424,10 @@ interface nsIApplicationUpdateService : nsISupports
/**
* Whether or not the Update Service can download and install updates.
* This is a function of whether or not the current user has access
* privileges to the install directory.
* On Windows, this is a function of whether or not the maintenance service
* is installed and enabled. On other systems, and as a fallback on Windows,
* this depends on whether the current user has write access to the install
* directory.
*/
readonly attribute boolean canApplyUpdates;

View File

@ -572,52 +572,61 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
}
}
try {
var updateTestFile = getUpdateFile([FILE_PERMS_TEST]);
LOG("gCanApplyUpdates - testing write access " + updateTestFile.path);
testWriteAccess(updateTestFile, false);
let useService = false;
if (shouldUseService() && isServiceInstalled()) {
// No need to perform directory write checks, the maintenance service will
// be able to write to all directories.
LOG("gCanApplyUpdates - bypass the write checks because we'll use the service");
useService = true;
}
if (!useService) {
try {
var updateTestFile = getUpdateFile([FILE_PERMS_TEST]);
LOG("gCanApplyUpdates - testing write access " + updateTestFile.path);
testWriteAccess(updateTestFile, false);
#ifdef XP_WIN
var sysInfo = Cc["@mozilla.org/system-info;1"].
getService(Ci.nsIPropertyBag2);
var sysInfo = Cc["@mozilla.org/system-info;1"].
getService(Ci.nsIPropertyBag2);
// Example windowsVersion: Windows XP == 5.1
var windowsVersion = sysInfo.getProperty("version");
LOG("gCanApplyUpdates - windowsVersion = " + windowsVersion);
/**
# For Vista, updates can be performed to a location requiring admin
# privileges by requesting elevation via the UAC prompt when launching
# updater.exe if the appDir is under the Program Files directory
# (e.g. C:\Program Files\) and UAC is turned on and we can elevate
# (e.g. user has a split token).
#
# Note: this does note attempt to handle the case where UAC is turned on
# and the installation directory is in a restricted location that
# requires admin privileges to update other than Program Files.
*/
var userCanElevate = false;
if (parseFloat(windowsVersion) >= 6) {
try {
var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
// KEY_UPDROOT will fail and throw an exception if
// appDir is not under the Program Files, so we rely on that
var dir = fileLocator.get(KEY_UPDROOT, Ci.nsIFile);
// appDir is under Program Files, so check if the user can elevate
userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).
userCanElevate;
LOG("gCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate);
}
catch (ex) {
// When the installation directory is not under Program Files,
// fall through to checking if write access to the
// installation directory is available.
LOG("gCanApplyUpdates - on Vista, appDir is not under Program Files");
}
}
// Example windowsVersion: Windows XP == 5.1
var windowsVersion = sysInfo.getProperty("version");
LOG("gCanApplyUpdates - windowsVersion = " + windowsVersion);
/**
# For Vista, updates can be performed to a location requiring admin
# privileges by requesting elevation via the UAC prompt when launching
# updater.exe if the appDir is under the Program Files directory
# (e.g. C:\Program Files\) and UAC is turned on and we can elevate
# (e.g. user has a split token).
#
# Note: this does note attempt to handle the case where UAC is turned on
# and the installation directory is in a restricted location that
# requires admin privileges to update other than Program Files.
*/
var userCanElevate = false;
if (parseFloat(windowsVersion) >= 6) {
try {
var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
// KEY_UPDROOT will fail and throw an exception if
// appDir is not under the Program Files, so we rely on that
var dir = fileLocator.get(KEY_UPDROOT, Ci.nsIFile);
// appDir is under Program Files, so check if the user can elevate
userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).
userCanElevate;
LOG("gCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate);
}
catch (ex) {
// When the installation directory is not under Program Files,
// fall through to checking if write access to the
// installation directory is available.
LOG("gCanApplyUpdates - on Vista, appDir is not under Program Files");
}
}
/**
# On Windows, we no longer store the update under the app dir.
#
# If we are on Windows (including Vista, if we can't elevate) we need to
@ -636,25 +645,26 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
# (e.g. the user does not have a split token)
# 4) UAC is turned on and the user is already elevated, so they can't be
# elevated again
*/
if (!userCanElevate) {
// if we're unable to create the test file this will throw an exception.
var appDirTestFile = getAppBaseDir();
appDirTestFile.append(FILE_PERMS_TEST);
LOG("gCanApplyUpdates - testing write access " + appDirTestFile.path);
if (appDirTestFile.exists())
appDirTestFile.remove(false)
appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
appDirTestFile.remove(false);
}
*/
if (!userCanElevate) {
// if we're unable to create the test file this will throw an exception.
var appDirTestFile = getAppBaseDir();
appDirTestFile.append(FILE_PERMS_TEST);
LOG("gCanApplyUpdates - testing write access " + appDirTestFile.path);
if (appDirTestFile.exists())
appDirTestFile.remove(false)
appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
appDirTestFile.remove(false);
}
#endif //XP_WIN
}
catch (e) {
LOG("gCanApplyUpdates - unable to apply updates. Exception: " + e);
// No write privileges to install directory
submitHasPermissionsTelemetryPing(false);
return false;
}
}
catch (e) {
LOG("gCanApplyUpdates - unable to apply updates. Exception: " + e);
// No write privileges to install directory
submitHasPermissionsTelemetryPing(false);
return false;
}
} // if (!useService)
if (!hasUpdateMutex()) {
LOG("gCanApplyUpdates - unable to apply updates because another instance" +
@ -1116,6 +1126,33 @@ function shouldUseService() {
#endif
}
/**
* Determines if the service is is installed and enabled or not.
*
* @return true if the service should be used for updates,
* is installed and enabled.
*/
function isServiceInstalled() {
#ifdef XP_WIN
let installed = 0;
try {
let wrk = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Mozilla\\MaintenanceService",
wrk.ACCESS_READ | wrk.WOW64_64);
installed = wrk.readIntValue("Installed");
wrk.close();
} catch(e) {
}
installed = installed == 1; // convert to bool
LOG("isServiceInstalled = " + installed);
return installed;
#else
return false;
#endif
}
/**
# Writes the update's application version to a file in the patch directory. If
# the update doesn't provide application version information via the
@ -2243,7 +2280,7 @@ UpdateService.prototype = {
* service was at some point installed, but is now uninstalled.
*/
_sendServiceInstalledTelemetryPing: function AUS__svcInstallTelemetryPing() {
let installed = 0;
let installed = isServiceInstalled(); // Is the service installed?
let attempted = 0;
try {
let wrk = Cc["@mozilla.org/windows-registry-key;1"].
@ -2251,14 +2288,14 @@ UpdateService.prototype = {
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Mozilla\\MaintenanceService",
wrk.ACCESS_READ | wrk.WOW64_64);
// Was the service at some point installed, but is now uninstalled?
attempted = wrk.readIntValue("Attempted");
installed = wrk.readIntValue("Installed");
wrk.close();
} catch(e) {
}
try {
let h = Services.telemetry.getHistogramById("UPDATER_SERVICE_INSTALLED");
h.add(installed);
h.add(Number(installed));
} catch(e) {
// Don't allow any exception to be propagated.
Cu.reportError(e);
@ -4270,7 +4307,7 @@ Downloader.prototype = {
"max fail: " + maxFail + ", " + "retryTimeout: " + retryTimeout);
if (Components.isSuccessCode(status)) {
if (this._verifyDownload()) {
state = shouldUseService() ? STATE_PENDING_SVC : STATE_PENDING
state = shouldUseService() ? STATE_PENDING_SVC : STATE_PENDING;
if (this.background) {
shouldShowPrompt = !getCanStageUpdates();
}

View File

@ -12,7 +12,7 @@
* implementation of this interface for non-Windows systems, for testing and
* development purposes only.
*/
[scriptable, uuid(ac813696-3b0a-4259-bce1-1d078021ebbe)]
[scriptable, uuid(c5a654c8-2443-47ce-9322-d150af3ca526)]
interface nsIWinMetroUtils : nsISupports
{
/* Fullscreen landscape orientation */
@ -66,6 +66,11 @@ interface nsIWinMetroUtils : nsISupports
*/
void launchInDesktop(in AString aPath, in AString aArguments);
/**
* Displays a native Windows 8 toast.
*/
void showNativeToast(in AString aTitle, in AString aMessage, in AString anImage);
/**
* Secondary tiles are a Windows 8 specific feature for pinning new tiles
* to the start screen. Tiles can later be activated whether the browser is

View File

@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 4; 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 "ToastNotificationHandler.h"
#include "MetroUtils.h"
#include "mozilla/Services.h"
#include "FrameworkView.h"
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Data::Xml::Dom;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace mozilla;
using namespace ABI::Windows::UI::Notifications;
typedef __FITypedEventHandler_2_Windows__CUI__CNotifications__CToastNotification_IInspectable_t ToastActivationHandler;
void ToastNotificationHandler::DisplayNotification(HSTRING title, HSTRING msg, HSTRING imagePath) {
ComPtr<IToastNotificationManagerStatics> toastNotificationManagerStatics;
AssertHRESULT(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(),
toastNotificationManagerStatics.GetAddressOf()));
ComPtr<IXmlDocument> toastXml;
toastNotificationManagerStatics->GetTemplateContent(ToastTemplateType::ToastTemplateType_ToastImageAndText03, &toastXml);
ComPtr<IXmlNodeList> toastTextElements, toastImageElements;
ComPtr<IXmlNode> titleTextNodeRoot, msgTextNodeRoot, imageNodeRoot, srcAttribute;
HSTRING textNodeStr, imageNodeStr, srcNodeStr;
HSTRING_HEADER textHeader, imageHeader, srcHeader;
WindowsCreateStringReference(L"text", 4, &textHeader, &textNodeStr);
WindowsCreateStringReference(L"image", 5, &imageHeader, &imageNodeStr);
WindowsCreateStringReference(L"src", 3, &srcHeader, &srcNodeStr);
toastXml->GetElementsByTagName(textNodeStr, &toastTextElements);
toastXml->GetElementsByTagName(imageNodeStr, &toastImageElements);
AssertHRESULT(toastTextElements->Item(0, &titleTextNodeRoot));
AssertHRESULT(toastTextElements->Item(1, &msgTextNodeRoot));
AssertHRESULT(toastImageElements->Item(0, &imageNodeRoot));
ComPtr<IXmlNamedNodeMap> attributes;
AssertHRESULT(imageNodeRoot->get_Attributes(&attributes));
AssertHRESULT(attributes->GetNamedItem(srcNodeStr, &srcAttribute));
SetNodeValueString(title, titleTextNodeRoot.Get(), toastXml.Get());
SetNodeValueString(msg, msgTextNodeRoot.Get(), toastXml.Get());
SetNodeValueString(imagePath, srcAttribute.Get(), toastXml.Get());
ComPtr<IToastNotification> notification;
ComPtr<IToastNotificationFactory> factory;
AssertHRESULT(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(),
factory.GetAddressOf()));
AssertHRESULT(factory->CreateToastNotification(toastXml.Get(), &notification));
EventRegistrationToken activatedToken;
AssertHRESULT(notification->add_Activated(Callback<ToastActivationHandler>(this,
&ToastNotificationHandler::OnActivate).Get(), &activatedToken));
ComPtr<IToastNotifier> notifier;
toastNotificationManagerStatics->CreateToastNotifier(&notifier);
notifier->Show(notification.Get());
}
void ToastNotificationHandler::SetNodeValueString(HSTRING inputString, ComPtr<IXmlNode> node, ComPtr<IXmlDocument> xml) {
ComPtr<IXmlText> inputText;
ComPtr<IXmlNode> inputTextNode, pAppendedChild;
AssertHRESULT(xml->CreateTextNode(inputString, &inputText));
AssertHRESULT(inputText.As(&inputTextNode));
AssertHRESULT(node->AppendChild(inputTextNode.Get(), &pAppendedChild));
}
HRESULT ToastNotificationHandler::OnActivate(IToastNotification *notification, IInspectable *inspectable) {
MetroUtils::FireObserver("metro_native_toast_clicked");
return S_OK;
}

View File

@ -0,0 +1,26 @@
/* -*- Mode: C++; tab-width: 4; 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/. */
#pragma once
#include <windows.ui.notifications.h>
#include <windows.data.xml.dom.h>
#include "mozwrlbase.h"
using namespace Microsoft::WRL;
class ToastNotificationHandler {
typedef ABI::Windows::UI::Notifications::IToastNotification IToastNotification;
typedef ABI::Windows::Data::Xml::Dom::IXmlNode IXmlNode;
typedef ABI::Windows::Data::Xml::Dom::IXmlDocument IXmlDocument;
void SetNodeValueString(HSTRING inputString, ComPtr<IXmlNode> node, ComPtr<IXmlDocument> xml);
public:
ToastNotificationHandler() {};
~ToastNotificationHandler() {};
void DisplayNotification(HSTRING title, HSTRING msg, HSTRING imagePath);
HRESULT OnActivate(IToastNotification *notification, IInspectable *inspectable);
};

View File

@ -15,6 +15,7 @@ CPP_SOURCES += [
'MetroInput.cpp',
'MetroUtils.cpp',
'MetroWidget.cpp',
'ToastNotificationHandler.cpp',
'UIAAccessibilityBridge.cpp',
'UIABridge.cpp',
'nsMetroFilePicker.cpp',

View File

@ -9,6 +9,7 @@
#include "FrameworkView.h"
#include "MetroApp.h"
#include "nsIWindowsRegKey.h"
#include "ToastNotificationHandler.h"
#include <shldisp.h>
#include <shellapi.h>
@ -339,6 +340,24 @@ nsWinMetroUtils::LaunchInDesktop(const nsAString &aPath, const nsAString &aArgum
if (!ShellExecuteEx(&sinfo)) {
return NS_ERROR_FAILURE;
}
}
NS_IMETHODIMP
nsWinMetroUtils::ShowNativeToast(const nsAString &aTitle,
const nsAString &aMessage, const nsAString &anImage)
{
// Firefox is in the foreground, no need for a notification.
if (::GetActiveWindow() == ::GetForegroundWindow()) {
return NS_OK;
}
ToastNotificationHandler* notification_handler =
new ToastNotificationHandler;
HSTRING title = HStringReference(aTitle.BeginReading()).Get();
HSTRING msg = HStringReference(aMessage.BeginReading()).Get();
HSTRING imagePath = HStringReference(anImage.BeginReading()).Get();
notification_handler->DisplayNotification(title, msg, imagePath);
return NS_OK;
}