Bug 404580 Provide information like preview text, subject and sender in mail notification window - as in Thunderbird ui-r=Neil r=Neil.
authorPhilip Chee <philip.chee@gmail.com>
Thu, 17 Jan 2013 21:37:34 +0800
changeset 14732 3b6458d6554349de71931b0ec8bcef15f60a0c88
parent 14731 9876dc5fd5072688c0841347793a6c6388cb9904
child 14733 393bcf57ae3143521729b1741e997c7b6cc76ea1
push id867
push userbugzilla@standard8.plus.com
push dateMon, 01 Apr 2013 20:44:27 +0000
treeherdercomm-beta@797726b8d244 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersNeil, Neil
bugs404580
Bug 404580 Provide information like preview text, subject and sender in mail notification window - as in Thunderbird ui-r=Neil r=Neil.
mailnews/base/src/nsMessengerUnixIntegration.cpp
mailnews/base/src/nsMessengerUnixIntegration.h
mailnews/base/src/nsMessengerWinIntegration.cpp
mailnews/base/src/nsMessengerWinIntegration.h
suite/browser/browser-prefs.js
suite/locales/en-US/chrome/mailnews/messenger.properties
suite/mailnews/jar.mn
suite/mailnews/newmailalert.css
suite/mailnews/newmailalert.js
suite/mailnews/newmailalert.xul
suite/themes/classic/jar.mn
suite/themes/classic/messenger/newmailalert.css
suite/themes/modern/jar.mn
suite/themes/modern/messenger/newmailalert.css
--- a/mailnews/base/src/nsMessengerUnixIntegration.cpp
+++ b/mailnews/base/src/nsMessengerUnixIntegration.cpp
@@ -145,17 +145,16 @@ nsresult nsMessengerUnixIntegration::Get
   NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
   nsCOMPtr<nsIStringBundle> bundle;
   bundleService->CreateBundle("chrome://messenger/locale/messenger.properties",
                               getter_AddRefs(bundle));
   bundle.swap(*aBundle);
   return NS_OK;
 }
 
-#ifdef MOZ_THUNDERBIRD
 bool
 nsMessengerUnixIntegration::BuildNotificationTitle(nsIMsgFolder *aFolder, nsIStringBundle *aBundle, nsString &aTitle)
 {
   nsString accountName;
   aFolder->GetPrettiestName(accountName);
 
   int32_t numNewMessages = 0;
   aFolder->GetNumNewMessages(true, &numNewMessages);
@@ -329,68 +328,55 @@ nsMessengerUnixIntegration::BuildNotific
     alertBody.Append(StringHead(previewString, previewLength));
 
   if (alertBody.IsEmpty())
     return false;
 
   aBody.Assign(alertBody);
   return true;
 }
-#endif
 
 nsresult nsMessengerUnixIntegration::ShowAlertMessage(const nsAString& aAlertTitle, const nsAString& aAlertText, const nsACString& aFolderURI)
 {
   nsresult rv;
   // if we are already in the process of showing an alert, don't try to show another....
   if (mAlertInProgress)
     return NS_OK;
 
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
   NS_ENSURE_SUCCESS(rv, rv);
   bool showAlert = true;
   prefBranch->GetBoolPref(SHOW_ALERT_PREF, &showAlert);
 
   if (showAlert)
   {
     mAlertInProgress = true;
-#ifdef MOZ_THUNDERBIRD
     nsCOMPtr<nsIAlertsService> alertsService(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID, &rv));
     if (NS_SUCCEEDED(rv)) {
       rv = alertsService->ShowAlertNotification(NS_LITERAL_STRING(NEW_MAIL_ALERT_ICON),
                                                 aAlertTitle,
                                                 aAlertText,
                                                 false,
                                                 NS_ConvertASCIItoUTF16(aFolderURI),
                                                 this,
                                                 EmptyString());
       if (NS_SUCCEEDED(rv))
         return rv;
     }
     AlertFinished();
     rv = ShowNewAlertNotification(false);
 
-#else
-    nsCOMPtr<nsIAlertsService> alertsService (do_GetService(NS_ALERTSERVICE_CONTRACTID, &rv));
-    if (NS_SUCCEEDED(rv))
-    {
-      rv = alertsService->ShowAlertNotification(NS_LITERAL_STRING(NEW_MAIL_ALERT_ICON), aAlertTitle,
-                                                aAlertText, true,
-                                                NS_ConvertASCIItoUTF16(aFolderURI), this,
-                                                EmptyString());
-    }
-#endif
   }
 
   if (NS_FAILED(rv)) // go straight to showing the system tray icon.
     AlertFinished();
 
   return rv;
 }
 
-#ifdef MOZ_THUNDERBIRD
 // Opening Thunderbird's new mail alert notification window for not supporting libnotify
 // aUserInitiated --> true if we are opening the alert notification in response to a user action
 //                    like clicking on the biff icon
 nsresult nsMessengerUnixIntegration::ShowNewAlertNotification(bool aUserInitiated)
 {
 
   nsresult rv;
 
@@ -440,17 +426,16 @@ nsresult nsMessengerUnixIntegration::Sho
                             getter_AddRefs(newWindow));
 
     if (NS_FAILED(rv))
       AlertFinished();
   }
 
   return rv;
 }
-#endif
 
 nsresult nsMessengerUnixIntegration::AlertFinished()
 {
   mAlertInProgress = false;
   return NS_OK;
 }
 
 nsresult nsMessengerUnixIntegration::AlertClicked()
@@ -491,17 +476,16 @@ void nsMessengerUnixIntegration::FillToo
     weakReference = do_QueryElementAt(mFoldersWithNewMail, i);
     folder = do_QueryReferent(weakReference);
     folder->GetChildWithURI(folderUri, true, true,
                             getter_AddRefs(folderWithNewMail));
   }
 
   if (folder && folderWithNewMail)
   {
-#ifdef MOZ_THUNDERBIRD
     nsCOMPtr<nsIStringBundle> bundle;
     GetStringBundle(getter_AddRefs(bundle));
 
     if (!bundle)
       return;
 
     // Create the notification title
     nsString alertTitle;
@@ -573,43 +557,16 @@ void nsMessengerUnixIntegration::FillToo
 
     uint32_t dateInSeconds = 0;
     if (NS_FAILED(lastMsgHdr->GetDateInSeconds(&dateInSeconds)))
       return;
 
     // Write the newest message timestamp to the appropriate
     // mapping in our hashtable of MRUTime's.
     PutMRUTimestampForFolder(folder, dateInSeconds);
-#else
-    nsString accountName;
-    folder->GetPrettiestName(accountName);
-
-    nsCOMPtr<nsIStringBundle> bundle;
-    GetStringBundle(getter_AddRefs(bundle));
-    if (bundle)
-    {
-      int32_t numNewMessages = 0;
-      folder->GetNumNewMessages(true, &numNewMessages);
-      nsAutoString numNewMsgsText;
-      numNewMsgsText.AppendInt(numNewMessages);
-
-      const PRUnichar *formatStrings[] =
-      {
-        numNewMsgsText.get(),
-      };
-
-      nsString finalText;
-      if (numNewMessages == 1)
-        bundle->FormatStringFromName(NS_LITERAL_STRING("biffNotification_message").get(), formatStrings, 1, getter_Copies(finalText));
-      else
-        bundle->FormatStringFromName(NS_LITERAL_STRING("biffNotification_messages").get(), formatStrings, 1, getter_Copies(finalText));
-
-      ShowAlertMessage(accountName, finalText, EmptyCString());
-    } // if we got a bundle
-#endif
   } // if we got a folder
 }
 
 // get the first top level folder which we know has new mail, then enumerate over all the subfolders
 // looking for the first real folder with new mail. Return the folderURI for that folder.
 nsresult nsMessengerUnixIntegration::GetFirstFolderWithNewMail(nsACString& aFolderURI)
 {
   nsresult rv;
@@ -770,21 +727,19 @@ NS_IMETHODIMP
 nsMessengerUnixIntegration::OnStartRunningUrl(nsIURI *aUrl)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMessengerUnixIntegration::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
 {
-#ifdef MOZ_THUNDERBIRD
   if (NS_SUCCEEDED(aExitCode))
     // preview fetch is done.
     FillToolTipInfo();
-#endif
   return NS_OK;
 }
 
 nsresult
 nsMessengerUnixIntegration::GetMRUTimestampForFolder(nsIMsgFolder *aFolder,
                                                      uint32_t *aLastMRUTime)
 {
   nsCOMPtr<nsIMsgFolder> rootFolder = nullptr;
@@ -794,26 +749,23 @@ nsMessengerUnixIntegration::GetMRUTimest
   nsCString rootFolderURI;
   rootFolder->GetURI(rootFolderURI);
   if (!mLastMRUTimes.Get(rootFolderURI, aLastMRUTime))
     aLastMRUTime = 0;
 
   return NS_OK;
 }
 
-#ifdef MOZ_THUNDERBIRD
 nsresult
 nsMessengerUnixIntegration::PutMRUTimestampForFolder(nsIMsgFolder *aFolder,
                                                      uint32_t aLastMRUTime)
 {
   nsresult rv;
   nsCOMPtr<nsIMsgFolder> rootFolder = nullptr;
   rv = aFolder->GetRootFolder(getter_AddRefs(rootFolder));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString rootFolderURI;
   rootFolder->GetURI(rootFolderURI);
   mLastMRUTimes.Put(rootFolderURI, aLastMRUTime);
 
   return NS_OK;
 }
-#endif
-
--- a/mailnews/base/src/nsMessengerUnixIntegration.h
+++ b/mailnews/base/src/nsMessengerUnixIntegration.h
@@ -40,22 +40,20 @@ private:
   nsresult ShowAlertMessage(const nsAString& aAlertTitle, const nsAString& aAlertText, const nsACString& aFolderURI);
   nsresult GetFirstFolderWithNewMail(nsACString& aFolderURI);
   nsresult GetStringBundle(nsIStringBundle **aBundle);
   nsresult AlertFinished();
   nsresult AlertClicked();
   void FillToolTipInfo();
   nsresult GetMRUTimestampForFolder(nsIMsgFolder *aFolder, uint32_t *aLastMRUTime);
 
-#ifdef MOZ_THUNDERBIRD
   bool BuildNotificationBody(nsIMsgDBHdr *aHdr, nsIStringBundle *Bundle, nsString &aBody);
   bool BuildNotificationTitle(nsIMsgFolder *aFolder, nsIStringBundle *aBundle, nsString &aTitle);
   nsresult ShowNewAlertNotification(bool aUserInitiated);
   nsresult PutMRUTimestampForFolder(nsIMsgFolder *aFolder, uint32_t aLastMRUTime);
-#endif
 
   nsCOMPtr<nsISupportsArray> mFoldersWithNewMail;  // keep track of all the root folders with pending new mail
   nsCOMPtr<nsIAtom> mBiffStateAtom;
   nsCOMPtr<nsIAtom> mNewMailReceivedAtom;
   bool mAlertInProgress;
   nsDataHashtable<nsCStringHashKey, uint32_t> mLastMRUTimes; // We keep track of the last time we did a new mail notification for each account
   nsTArray<nsCString> mFetchingURIs;
 };
--- a/mailnews/base/src/nsMessengerWinIntegration.cpp
+++ b/mailnews/base/src/nsMessengerWinIntegration.cpp
@@ -63,16 +63,18 @@
 #define MAIL_COMMANDLINE_ARG " -mail"
 #define IDI_MAILBIFF 32576
 #define UNREAD_UPDATE_INTERVAL	(20 * 1000)	// 20 seconds
 #define ALERT_CHROME_URL "chrome://messenger/content/newmailalert.xul"
 #define NEW_MAIL_ALERT_ICON "chrome://messenger/skin/icons/new-mail-alert.png"
 #define SHOW_ALERT_PREF     "mail.biff.show_alert"
 #define SHOW_TRAY_ICON_PREF "mail.biff.show_tray_icon"
 #define SHOW_BALLOON_PREF   "mail.biff.show_balloon"
+#define SHOW_NEW_ALERT_PREF "mail.biff.show_new_alert"
+#define ALERT_ORIGIN_PREF   "ui.alertNotificationOrigin"
 
 // since we are including windows.h in this file, undefine get user name....
 #ifdef GetUserName
 #undef GetUserName
 #endif
 
 #ifndef NIIF_USER
 #define NIIF_USER       0x00000004
@@ -81,16 +83,23 @@
 #ifndef NIIF_NOSOUND
 #define NIIF_NOSOUND    0x00000010
 #endif
 
 #ifndef NIN_BALOONUSERCLICK
 #define NIN_BALLOONUSERCLICK (WM_USER + 5)
 #endif
 
+#ifndef MOZ_THUNDERBIRD
+// from LookAndFeel.h
+#define NS_ALERT_HORIZONTAL 1
+#define NS_ALERT_LEFT       2
+#define NS_ALERT_TOP        4
+#endif
+
 using namespace mozilla;
 
 // begin shameless copying from nsNativeAppSupportWin
 HWND hwndForDOMWindow( nsISupports *window )
 {
   nsCOMPtr<nsPIDOMWindow> win( do_QueryInterface(window) );
   if ( !win )
       return 0;
@@ -160,29 +169,27 @@ static void openMailWindow(const nsACStr
                                 "mail:3pane", nsCString(aFolderUri).get(), nsMsgKey_None);
   }
 }
 
 static void CALLBACK delayedSingleClick(HWND msgWindow, UINT msg, INT_PTR idEvent, DWORD dwTime)
 {
   ::KillTimer(msgWindow, idEvent);
 
-#ifdef MOZ_THUNDERBIRD
   // single clicks on the biff icon should re-open the alert notification
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMessengerOSIntegration> integrationService =
     do_GetService(NS_MESSENGEROSINTEGRATION_CONTRACTID, &rv);
   if (NS_SUCCEEDED(rv))
   {
     // we know we are dealing with the windows integration object
     nsMessengerWinIntegration * winIntegrationService = static_cast<nsMessengerWinIntegration*>
                                                                    (static_cast<nsIMessengerOSIntegration*>(integrationService.get()));
     winIntegrationService->ShowNewAlertNotification(true, EmptyString(), EmptyString());
   }
-#endif
 }
 
 // Window proc.
 static LRESULT CALLBACK MessageWindowProc( HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp )
 {
   if (msg == WM_USER)
   {
     if (lp == WM_LBUTTONDOWN)
@@ -443,17 +450,17 @@ nsresult nsMessengerWinIntegration::Show
     }
   }
 
   if (!showAlert || NS_FAILED(rv)) // go straight to showing the system tray icon.
     AlertFinished();
 
   return rv;
 }
-#else
+#endif
 // Opening Thunderbird's new mail alert notification window
 // aUserInitiated --> true if we are opening the alert notification in response to a user action
 //                    like clicking on the biff icon
 nsresult nsMessengerWinIntegration::ShowNewAlertNotification(bool aUserInitiated, const nsString& aAlertTitle, const nsString& aAlertText)
 {
   nsresult rv;
 
   // if we are already in the process of showing an alert, don't try to show another....
@@ -514,19 +521,57 @@ nsresult nsMessengerWinIntegration::Show
     scriptableUserInitiated->SetData(aUserInitiated);
     rv = argsArray->AppendElement(scriptableUserInitiated, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // pass in the alert origin
     nsCOMPtr<nsISupportsPRUint8> scriptableOrigin (do_CreateInstance(NS_SUPPORTS_PRUINT8_CONTRACTID));
     NS_ENSURE_TRUE(scriptableOrigin, NS_ERROR_FAILURE);
     scriptableOrigin->SetData(0);
-    int32_t origin = LookAndFeel::GetInt(LookAndFeel::eIntID_AlertNotificationOrigin);
-    if (origin && origin >= 0 && origin <= 7)
-      scriptableOrigin->SetData(origin);
+    int32_t origin = 0;
+#ifdef MOZ_THUNDERBIRD
+    origin = LookAndFeel::GetInt(LookAndFeel::eIntID_AlertNotificationOrigin);
+#else
+    // Get task bar window handle
+    HWND shellWindow = FindWindowW(L"Shell_TrayWnd", NULL);
+
+    rv = prefBranch->GetIntPref(ALERT_ORIGIN_PREF, &origin);
+    if (NS_FAILED(rv) && (shellWindow != NULL))
+    {
+      // Determine position
+      APPBARDATA appBarData;
+      appBarData.hWnd = shellWindow;
+      appBarData.cbSize = sizeof(appBarData);
+      if (SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData))
+      {
+        // Set alert origin as a bit field - see LookAndFeel.h
+        // 0 represents bottom right, sliding vertically.
+        switch(appBarData.uEdge)
+        {
+          case ABE_LEFT:
+            origin = NS_ALERT_HORIZONTAL | NS_ALERT_LEFT;
+            break;
+          case ABE_RIGHT:
+            origin = NS_ALERT_HORIZONTAL;
+            break;
+          case ABE_TOP:
+            origin = NS_ALERT_TOP;
+            // fall through for the right-to-left handling.
+          case ABE_BOTTOM:
+            // If the task bar is right-to-left,
+            // move the origin to the left
+            if (::GetWindowLong(shellWindow, GWL_EXSTYLE) &
+                  WS_EX_LAYOUTRTL)
+              origin |= NS_ALERT_LEFT;
+            break;
+        }
+      }
+    }
+#endif
+    scriptableOrigin->SetData(origin);
 
     rv = argsArray->AppendElement(scriptableOrigin, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
     nsCOMPtr<nsIDOMWindow> newWindow;
     rv = wwatch->OpenWindow(0, ALERT_CHROME_URL, "_blank",
                 "chrome,dialog=yes,titlebar=no,popup=yes", argsArray,
@@ -537,17 +582,16 @@ nsresult nsMessengerWinIntegration::Show
 
   // if the user has turned off the mail alert, or  openWindow generated an error,
   // then go straight to the system tray.
   if (!showAlert || NS_FAILED(rv))
     AlertFinished();
 
   return rv;
 }
-#endif
 
 nsresult nsMessengerWinIntegration::AlertFinished()
 {
   // okay, we are done showing the alert
   // now put an icon in the system tray, if allowed
   bool showTrayIcon = !mSuppressBiffIcon;
   if (showTrayIcon)
   {
@@ -562,33 +606,31 @@ nsresult nsMessengerWinIntegration::Aler
   }
   mSuppressBiffIcon = false;
   mAlertInProgress = false;
   return NS_OK;
 }
 
 nsresult nsMessengerWinIntegration::AlertClicked()
 {
-#ifdef MOZ_THUNDERBIRD
   nsresult rv;
   nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv,rv);
   nsCOMPtr<nsIMsgWindow> topMostMsgWindow;
   rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(topMostMsgWindow));
   if (topMostMsgWindow)
   {
     nsCOMPtr<nsIDOMWindow> domWindow;
     topMostMsgWindow->GetDomWindow(getter_AddRefs(domWindow));
     if (domWindow)
     {
       activateWindow(domWindow);
       return NS_OK;
     }
   }
-#endif
   // make sure we don't insert the icon in the system tray since the user clicked on the alert.
   mSuppressBiffIcon = true;
   nsCString folderURI;
   GetFirstFolderWithNewMail(folderURI);
   openMailWindow(folderURI);
   return NS_OK;
 }
 
@@ -695,20 +737,27 @@ void nsMessengerWinIntegration::FillTool
     } // if we got a folder
   } // for each folder
 
   ::wcsncpy( sBiffIconData.szTip, toolTipText.get(), kMaxTooltipSize);
 
   if (!mBiffIconVisible)
   {
 #ifndef MOZ_THUNDERBIRD
+  nsresult rv;
+  bool showNewAlert = false;
+  nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  prefBranch->GetBoolPref(SHOW_NEW_ALERT_PREF, &showNewAlert);
+  if (!showNewAlert)
     ShowAlertMessage(accountName, animatedAlertText, EmptyCString());
-#else
+  else
+#endif
     ShowNewAlertNotification(false, accountName, animatedAlertText);
-#endif
   }
   else
    GenericShellNotify( NIM_MODIFY);
 }
 
 // get the first top level folder which we know has new mail, then enumerate over all the subfolders
 // looking for the first real folder with new mail. Return the folderURI for that folder.
 nsresult nsMessengerWinIntegration::GetFirstFolderWithNewMail(nsACString& aFolderURI)
--- a/mailnews/base/src/nsMessengerWinIntegration.h
+++ b/mailnews/base/src/nsMessengerWinIntegration.h
@@ -51,19 +51,18 @@ public:
   virtual ~nsMessengerWinIntegration();
   virtual nsresult Init();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMESSENGEROSINTEGRATION
   NS_DECL_NSIFOLDERLISTENER
   NS_DECL_NSIOBSERVER
 
-#ifdef MOZ_THUNDERBIRD
   nsresult ShowNewAlertNotification(bool aUserInitiated, const nsString& aAlertTitle, const nsString& aAlertText);
-#else
+#ifndef MOZ_THUNDERBIRD
   nsresult ShowAlertMessage(const nsString& aAlertTitle, const nsString& aAlertText, const nsACString& aFolderURI);
 #endif
 
 private:
   nsresult AlertFinished();
   nsresult AlertClicked();
 
   void InitializeBiffStatusIcon(); 
--- a/suite/browser/browser-prefs.js
+++ b/suite/browser/browser-prefs.js
@@ -324,16 +324,17 @@ pref("offline.download.download_messages
 pref("browser.offline-apps.notify", true);
 
 pref("browser.formfill.expire_days",        180);
 
 pref("mail.biff.alert.show_preview", true);
 pref("mail.biff.alert.show_subject", true);
 pref("mail.biff.alert.show_sender",  true);
 pref("mail.biff.alert.preview_length", 40);
+pref("mail.biff.show_new_alert",     true);
 
 pref("mailnews.ui.deleteMarksRead", true);
 
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 // (This is intentionally on the high side; see bugs 746055 and 768015.)
 pref("image.mem.max_decoded_image_kb", 256000);
 
--- a/suite/locales/en-US/chrome/mailnews/messenger.properties
+++ b/suite/locales/en-US/chrome/mailnews/messenger.properties
@@ -318,16 +318,22 @@ biffNotification_messages=has %1$S new m
 #  %2$S is a list of names and/or email addresses separated by biffNotification_separator
 #  %3$S is the number of new messages not displayed in the biff alert
 macBiffNotification_message=%1$S new message from %2$S.
 macBiffNotification_messages=%1$S new messages from %2$S.
 macBiffNotification_messages_extra=%1$S new messages from %2$S and %3$S more.
 # Used to separate names/email addresses in a list.  Note the trailing space ', '
 macBiffNotification_separator=,\u0020
 
+# LOCALIZATION NOTE(newMailNotification_message): %1$S is the name of the account %2$S is the number of new messages  
+newMailNotification_message=%1$S received %2$S new message
+
+# LOCALIZATION NOTE(newMailNotification_messages): %1$S is the name of the account %2$S is the number of new messages  
+newMailNotification_messages=%1$S received %2$S new messages
+
 # For the Quota tab in the mail folder properties dialog
 quotaUsedFree=%S of %S KB used
 quotaPercentUsed=%S%% full
 
 # for message views
 confirmViewDeleteTitle=Confirm
 confirmViewDeleteMessage=Are you sure you want to delete this view?
 
--- a/suite/mailnews/jar.mn
+++ b/suite/mailnews/jar.mn
@@ -53,16 +53,19 @@ messenger.jar:
     content/messenger/mailEditorOverlay.xul
     content/messenger/mailKeysOverlay.xul
     content/messenger/phishingDetector.js
     content/messenger/mailOverlay.xul
     content/messenger/mailOverlay.js
     content/messenger/mail-offline.js
     content/messenger/mailContextMenus.js
     content/messenger/msgFolderPickerOverlay.xul
+    content/messenger/newmailalert.css
+    content/messenger/newmailalert.js
+    content/messenger/newmailalert.xul
     content/messenger/start.xhtml
     content/messenger/messengerdnd.js
     content/messenger/mailPrefsOverlay.xul                                     (prefs/mailPrefsOverlay.xul)
     content/messenger/pref-mailnews.xul                                        (prefs/pref-mailnews.xul)
     content/messenger/pref-mailnews.js                                         (prefs/pref-mailnews.js)
     content/messenger/pref-notifications.xul                                   (prefs/pref-notifications.xul)
     content/messenger/pref-notifications.js                                    (prefs/pref-notifications.js)
     content/messenger/pref-junk.xul                                            (prefs/pref-junk.xul)
new file mode 100644
--- /dev/null
+++ b/suite/mailnews/newmailalert.css
@@ -0,0 +1,23 @@
+/* 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/. */
+
+#alertContainer {
+  opacity: 0;
+}
+
+#alertContainer[noanimation] {
+  opacity: 1;
+}
+
+#alertContainer[animate] {
+  animation-timing-function: ease-out;
+  animation-duration: 4s;
+  animation-fill-mode: both;
+  animation-name: alert-animation;
+}
+
+@keyframes alert-animation {
+  from {opacity: 0;}
+  to {opacity: 1;}
+}
copy from mail/base/content/newmailalert.js
copy to suite/mailnews/newmailalert.js
--- a/mail/base/content/newmailalert.js
+++ b/suite/mailnews/newmailalert.js
@@ -1,26 +1,26 @@
 /* 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/. */
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
-const HORIZONTAL = 1;
-const LEFT = 2;
-const TOP = 4;
+// Copied from nsILookAndFeel.h, see comments on eMetric_AlertNotificationOrigin
+const NS_ALERT_HORIZONTAL = 1;
+const NS_ALERT_LEFT = 2;
+const NS_ALERT_TOP = 4;
 
-var gSlideTime = 50;
 var gNumNewMsgsToShowInAlert = 4; // the more messages we show in the alert, the larger it will be
-var gOpenTime = 3000; // total time the alert should stay up once we are done animating.
+var gOpenTime = 4000; // total time the alert should stay up once we are done animating.
+
 var gAlertListener = null;
 var gPendingPreviewFetchRequests = 0;
 var gUserInitiated = false;
-var gFadeIncrement = .05;
-var gOrigin = 0;
+var gOrigin = 0; // Default value: alert from bottom right.
 
 function prefillAlertInfo()
 {
   // unwrap all the args....
   // arguments[0] --> array of folders with new mail
   // arguments[1] --> the observer to call back with notifications about the alert
   // arguments[2] --> user initiated boolean. true if the user initiated opening the alert 
   //                 (which means skip the fade effect and don't auto close the alert)
@@ -28,81 +28,85 @@ function prefillAlertInfo()
   var foldersWithNewMail = window.arguments[0];  
   gAlertListener = window.arguments[1];
   gUserInitiated = window.arguments[2];
   gOrigin = window.arguments[3];
 
   // For now just grab the first folder which should be a root folder
   // for the account that has new mail. If we can't find a folder, just
   // return to avoid the exception and empty dialog in upper left-hand corner.
-  let rootFolder;
-  if (foldersWithNewMail && foldersWithNewMail.Count() > 0)
-     rootFolder = foldersWithNewMail.GetElementAt(0)
-                    .QueryInterface(Components.interfaces.nsIWeakReference)
-                    .QueryReferent(Components.interfaces.nsIMsgFolder);
-  else
-   return;
+  var rootFolder;
+  if (!foldersWithNewMail || foldersWithNewMail.Count() < 1)
+    return;
+  rootFolder = foldersWithNewMail.GetElementAt(0)
+                                 .QueryInterface(Components.interfaces.nsIWeakReference)
+                                 .QueryReferent(Components.interfaces.nsIMsgFolder);
 
-  // generate an account label string based on the root folder
+  // Generate an account label string based on the root folder.
   var label = document.getElementById('alertTitle');
   var totalNumNewMessages = rootFolder.getNumNewMessages(true);
-  label.value = document.getElementById('bundle_messenger').getFormattedString(totalNumNewMessages == 1 ? "newMailNotification_message" : "newMailNotification_messages", 
-                                                                                     [rootFolder.prettiestName, totalNumNewMessages]);
+  var message = totalNumNewMessages == 1 ? "newMailNotification_message"
+                                         : "newMailNotification_messages";
+  label.value = document.getElementById('bundle_messenger')
+                        .getFormattedString(message, 
+                                            [rootFolder.prettiestName, totalNumNewMessages]);
 
-  // this is really the root folder and we have to walk through the list to find the real folder that has new mail in it...:(
-  var allFolders = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
+  // This is really the root folder and we have to walk through the list to
+  // find the real folder that has new mail in it...:(
+  var allFolders = Components.classes["@mozilla.org/supports-array;1"]
+                             .createInstance(Components.interfaces.nsISupportsArray);
   rootFolder.ListDescendents(allFolders);
   var numFolders = allFolders.Count();
   var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
   folderSummaryInfoEl.mMaxMsgHdrsInPopup = gNumNewMsgsToShowInAlert;
-  for (var folderIndex = 0; folderIndex < numFolders; folderIndex++)
+  for (let folderIndex = 0; folderIndex < numFolders; folderIndex++)
   {
-    var folder = allFolders.GetElementAt(folderIndex).QueryInterface(Components.interfaces.nsIMsgFolder);
+    var folder = allFolders.GetElementAt(folderIndex)
+                           .QueryInterface(Components.interfaces.nsIMsgFolder);
     const nsMsgFolderFlags = Components.interfaces.nsMsgFolderFlags;
     if (folder.hasNewMessages && !(folder.flags & nsMsgFolderFlags.Virtual))
     {
       var asyncFetch = {};
       folderSummaryInfoEl.parseFolder(folder, new urlListener(folder), asyncFetch);
       if (asyncFetch.value)
         gPendingPreviewFetchRequests++;
     }
   }
 }
 
 function urlListener(aFolder)
 {
   this.mFolder = aFolder;
 }
 
-urlListener.prototype = {
+urlListener.prototype =
+{
   OnStartRunningUrl: function(aUrl)
   {
   },
 
   OnStopRunningUrl: function(aUrl, aExitCode)
   {
     var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
-    var asyncFetch = {};
-    folderSummaryInfoEl.parseFolder(this.mFolder, null, asyncFetch);
+    folderSummaryInfoEl.parseFolder(this.mFolder, null, {});
     gPendingPreviewFetchRequests--;
 
     // when we are done running all of our urls for fetching the preview text,
     // start the alert.
     if (!gPendingPreviewFetchRequests)
       showAlert();
   }
 }
 
 function onAlertLoad()
 {
   prefillAlertInfo();
   // read out our initial settings from prefs.
   try 
   {
-    gSlideTime = Services.prefs.getIntPref("alerts.slideIncrementTime");
     gOpenTime = Services.prefs.getIntPref("alerts.totalOpenTime");
   } catch (ex) {}
   
   // bogus call to make sure the window is moved offscreen until we are ready for it.
   resizeAlert(true);
 
   // if we aren't waiting to fetch preview text, then go ahead and 
   // start showing the alert.
@@ -110,81 +114,68 @@ function onAlertLoad()
     setTimeout(showAlert, 0); // let the JS thread unwind, to give layout 
                               // a chance to recompute the styles and widths for our alert text.
 }
 
 // If the user initiated the alert, show it right away, otherwise start opening the alert with
 // the fade effect. 
 function showAlert()
 {
-  if (!gUserInitiated) // set the initial opacity before we resize the window
-    document.getElementById('alertContainer').style.opacity = 0;
-  
   // resize the alert based on our current content  
   resizeAlert(false);
   
+  var alertContainer = document.getElementById("alertContainer");
+  // Don't fade in if the user opened the alert or the pref is true.
+  if (gUserInitiated ||
+      Services.prefs.getBoolPref("alerts.disableSlidingEffect")) {
+    alertContainer.setAttribute("noanimation", true);
+    setTimeout(closeAlert, gOpenTime);
+    return;
+  }
+  
   if (document.getElementById('folderSummaryInfo').hasMessages)
   {
-    if (!gUserInitiated) // don't fade in if the user opened the alert
-      setTimeout(fadeOpen, gSlideTime);
+    alertContainer.addEventListener("animationend", function hideAlert(event) {
+      if (event.animationName == "alert-animation") {
+        alertContainer.removeEventListener("animationend", hideAlert, false);
+        let remaining = Math.max(Math.round(gOpenTime - event.elapsedTime * 1000), 0);
+        setTimeout(closeAlert, remaining);
+      }
+    }, false);
+    alertContainer.setAttribute("animate", true);
   }
   else
+  {
     closeAlert(); // no mail, so don't bother showing the alert...
+  }
 }
 
 function resizeAlert(aMoveOffScreen)
 {
-  // sizeToContent is not working. It isn't honoring the max widths we are attaching to our inner
-  // objects like the folder summary element. While the folder summary element is cropping, 
-  // sizeToContent ends up thinking the window needs to be much wider than it should be. 
-  // use resizeTo and make up our measurements...
-  //sizeToContent();
-  
-  // Use the wider of the alert groove and the folderSummaryInfo box, then 
-  // add on the width of alertImageBox + some small amount of fudge. For the height, 
-  // just use the size of the alertBox, that appears to be pretty accurate.
-  var windowWidth = Math.max (document.getBoxObjectFor(document.getElementById('alertGroove')).width,
-                              document.getBoxObjectFor(document.getElementById('folderSummaryInfo')).width);
-  resizeTo(windowWidth + document.getBoxObjectFor(document.getElementById('alertImageBox')).width + 30, 
-           document.getBoxObjectFor(document.getElementById('alertBox')).height + 10);                     
+  var alertTextBox = document.getElementById("alertTextBox");
+  var alertImageBox = document.getElementById("alertImageBox");
+  alertImageBox.style.minHeight = alertTextBox.scrollHeight + "px";
+
+  sizeToContent();
   
   // leftover hack to get the window properly hidden when we first open it
   if (aMoveOffScreen)
     window.outerHeight = 1;
 
-  // Determine position and move window
-  var x = gOrigin & LEFT ? screen.availLeft :
-          (screen.availLeft + screen.availWidth - window.outerWidth);
-  var y = gOrigin & TOP ? screen.availTop :
-          (screen.availTop + screen.availHeight - window.outerHeight);
-  window.moveTo(x, y);
-}
+  // Determine position
+  var x = gOrigin & NS_ALERT_LEFT ? screen.availLeft :
+          screen.availLeft + screen.availWidth - window.outerWidth;
+  var y = gOrigin & NS_ALERT_TOP ? screen.availTop :
+          screen.availTop + screen.availHeight - window.outerHeight;
 
-function fadeOpen()
-{
-  var alertContainer = document.getElementById('alertContainer');
-  var newOpacity = parseFloat(window.getComputedStyle(alertContainer, "").opacity) + gFadeIncrement;
-  alertContainer.style.opacity = newOpacity;
-  
-  if (newOpacity < 1.0)    
-    setTimeout(fadeOpen, gSlideTime);
-  else // switch gears and start closing the alert
-    setTimeout(fadeClose, gOpenTime);  
-}
+  // Offset the alert by 10 pixels from the edge of the screen
+  y += gOrigin & NS_ALERT_TOP ? 10 : -10;
+  x += gOrigin & NS_ALERT_LEFT ? 10 : -10;
 
-function fadeClose()
-{
-  var alertContainer = document.getElementById('alertContainer');
-  var newOpacity = parseFloat(window.getComputedStyle(alertContainer, "").opacity) - gFadeIncrement;
-  alertContainer.style.opacity = newOpacity;
-  
-  if (newOpacity <= 0)
-    closeAlert();
-  else
-    setTimeout(fadeClose, gSlideTime);
+  window.moveTo(x, y);
 }
 
 function closeAlert()
 {
   if (gAlertListener)
     gAlertListener.observe(null, "alertfinished", ""); 
   window.close(); 
 }
copy from mail/base/content/newmailalert.xul
copy to suite/mailnews/newmailalert.xul
--- a/mail/base/content/newmailalert.xul
+++ b/suite/mailnews/newmailalert.xul
@@ -1,37 +1,35 @@
 <?xml version="1.0"?>
 
 <!-- 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/. -->
 
+<?xml-stylesheet href="chrome://messenger/content/newmailalert.css" type="text/css"?>
 <?xml-stylesheet href="chrome://messenger/skin/newmailalert.css" type="text/css"?>
 
 <window id="newMailAlertNotification"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         windowtype="alert:alert"
         role="alert"
         align="start"
         onload="onAlertLoad()">
 
   <stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
   <script type="application/javascript" src="chrome://messenger/content/newmailalert.js"/>
 
   <stack id="alertContainer" mousethrough="always">
     <hbox id="alertBox">
-      <hbox id ="alertImageBox" align="center" valign="center">
+      <hbox id ="alertImageBox" align="center" pack="center">
         <image id="alertImage"/>
       </hbox>
 
       <vbox id="alertTextBox">
         <label id="alertTitle"/>
         <separator id="alertGroove" class="groove"/>
         <folderSummary id="folderSummaryInfo" mousethrough="never"/>
       </vbox>
     </hbox>
 
-    <hbox align="top">
-      <spacer flex="1"/>
-      <toolbarbutton id="closeButton" onclick="closeAlert();"/>
-    </hbox>
+    <toolbarbutton id="closeButton" top="0" right="0" onclick="closeAlert();"/>
   </stack>
 </window>
--- a/suite/themes/classic/jar.mn
+++ b/suite/themes/classic/jar.mn
@@ -251,16 +251,17 @@ classic.jar:
   skin/classic/messenger/dialogs.css                                    (messenger/dialogs.css)
   skin/classic/messenger/accountWizard.css                              (messenger/accountWizard.css)
   skin/classic/messenger/folderMenus.css                                (messenger/folderMenus.css)
   skin/classic/messenger/folderPane.css                                 (messenger/folderPane.css)
   skin/classic/messenger/accountCentral.css                             (messenger/accountCentral.css)
   skin/classic/messenger/addressingWidget.css                           (messenger/addressingWidget.css)
   skin/classic/messenger/messageWindow.css                              (messenger/messageWindow.css)
   skin/classic/messenger/messenger.css                                  (messenger/messenger.css)
+  skin/classic/messenger/newmailalert.css                               (messenger/newmailalert.css)
   skin/classic/messenger/prefPanels.css                                 (messenger/prefPanels.css)
   skin/classic/messenger/subscribe.css                                  (messenger/subscribe.css)
   skin/classic/messenger/threadPane.css                                 (messenger/threadPane.css)
   skin/classic/messenger/threadPaneLabels.css                           (messenger/threadPaneLabels.css)
   skin/classic/messenger/messageBody.css                                (messenger/messageBody.css)
   skin/classic/messenger/start.css                                      (messenger/start.css)
   skin/classic/messenger/virtualFolderListDialog.css                    (messenger/virtualFolderListDialog.css)
   skin/classic/messenger/icons/acct-compose.png                         (messenger/icons/acct-compose.png)
copy from mail/themes/qute/mail/newmailalert.css
copy to suite/themes/classic/messenger/newmailalert.css
--- a/mail/themes/qute/mail/newmailalert.css
+++ b/suite/themes/classic/messenger/newmailalert.css
@@ -8,44 +8,34 @@
   ======================================================================= */
 
 @import url("chrome://messenger/skin/");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 #newMailAlertNotification {
   min-height: 60px;
-  border: ridge #5486DA 4px;
-  background-color: -moz-Dialog;
-  color: -moz-DialogText;
+  border: ridge SteelBlue 4px;
 }
 
 #alertImage {
   list-style-image: url("chrome://branding/content/icon64.png");
 }
 
 #alertImageBox {
-  -moz-margin-start: 4px;
-  -moz-margin-end: 6px;
-  min-height: 46px;
+  padding: 4px;
 }
 
 #alertTitle {
   font-weight: bold;
-  text-align: center;
-  /* this right margin keeps us from overlapping with the
-     close button. It's value should be related to the width
-     of the closeButtonImage
-  */
-  -moz-margin-end: 16px;
 }
 
 #alertTextBox {
-  -moz-padding-end: 10px;
-  padding-top: 5px;
+  padding: 4px;
+  -moz-padding-end: 16px;
 }
 
 .folderSummary-message-row
 {
   /* This max width ends up dictating the overall width of the alert window
      because it controls how large the preview, subject and sender text can be
      before cropping kicks in */
   max-width: 450px;
@@ -65,26 +55,13 @@
 }
 
 .folderSummaryMessage:hover > .folderSummary-message-row {
   cursor: pointer;
   color: blue;
 }
 
 #closeButton {
-  list-style-image: url("chrome://messenger/skin/icons/close-button.png");
-  -moz-image-region: rect(0px, 16px, 16px, 0px);
+  list-style-image: url("chrome://navigator/skin/icons/close.gif");
   -moz-appearance: none;
   border: none !important;
   padding: 2px 0px 0px;
 }
-
-#closeButton > .toolbarbutton-icon {
-  -moz-margin-end: 0px; /* override toolkit's default value */
-}
-
-#closeButton:hover {
-  -moz-image-region: rect(0px, 32px, 16px, 16px);
-}
-
-#closeButton:hover:active {
-  -moz-image-region: rect(0px, 48px, 16px, 32px);
-}
--- a/suite/themes/modern/jar.mn
+++ b/suite/themes/modern/jar.mn
@@ -382,16 +382,17 @@ modern.jar:
   skin/modern/messenger/folderPaneExtras.css                       (messenger/folderPaneExtras.css)
   skin/modern/messenger/threadPaneExtras.css                       (messenger/threadPaneExtras.css)
   skin/modern/messenger/messageBody.css                            (messenger/messageBody.css)
   skin/modern/messenger/virtualFolderListDialog.css                (messenger/virtualFolderListDialog.css)
   skin/modern/messenger/messageHeader.css                          (messenger/messageHeader.css)
   skin/modern/messenger/messageKeywords.css                        (messenger/messageKeywords.css)
   skin/modern/messenger/messageWindow.css                          (messenger/messageWindow.css)
   skin/modern/messenger/messenger.css                              (messenger/messenger.css)
+  skin/modern/messenger/newmailalert.css                           (messenger/newmailalert.css)
   skin/modern/messenger/prefPanels.css                             (messenger/prefPanels.css)
   skin/modern/messenger/searchDialog.css                           (messenger/searchDialog.css)
   skin/modern/messenger/subscribe.css                              (messenger/subscribe.css)
   skin/modern/messenger/mailWindow1.css                            (messenger/mailWindow1.css)
   skin/modern/messenger/threadPane.css                             (messenger/threadPane.css)
   skin/modern/messenger/primaryToolbar.css                         (messenger/primaryToolbar.css)
   skin/modern/messenger/start.css                                  (messenger/start.css)
   skin/modern/messenger/addressbook/abResultsPane.css              (messenger/addressbook/abResultsPane.css)
copy from mail/themes/qute/mail/newmailalert.css
copy to suite/themes/modern/messenger/newmailalert.css
--- a/mail/themes/qute/mail/newmailalert.css
+++ b/suite/themes/modern/messenger/newmailalert.css
@@ -9,43 +9,33 @@
 
 @import url("chrome://messenger/skin/");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 #newMailAlertNotification {
   min-height: 60px;
   border: ridge #5486DA 4px;
-  background-color: -moz-Dialog;
-  color: -moz-DialogText;
 }
 
 #alertImage {
   list-style-image: url("chrome://branding/content/icon64.png");
 }
 
 #alertImageBox {
-  -moz-margin-start: 4px;
-  -moz-margin-end: 6px;
-  min-height: 46px;
+  padding: 4px;
 }
 
 #alertTitle {
   font-weight: bold;
-  text-align: center;
-  /* this right margin keeps us from overlapping with the
-     close button. It's value should be related to the width
-     of the closeButtonImage
-  */
-  -moz-margin-end: 16px;
 }
 
 #alertTextBox {
-  -moz-padding-end: 10px;
-  padding-top: 5px;
+  padding: 4px;
+  -moz-padding-end: 16px;
 }
 
 .folderSummary-message-row
 {
   /* This max width ends up dictating the overall width of the alert window
      because it controls how large the preview, subject and sender text can be
      before cropping kicks in */
   max-width: 450px;
@@ -56,35 +46,22 @@
   font-weight: bold;
 }
 
 .folderSummary-sender, .folderSummary-subject {
   cursor: inherit;
 }
 
 .folderSummary-previewText {
-  color: grey;
+  color: #8C99AB;
 }
 
 .folderSummaryMessage:hover > .folderSummary-message-row {
   cursor: pointer;
-  color: blue;
+  color: #0000FF;
 }
 
 #closeButton {
-  list-style-image: url("chrome://messenger/skin/icons/close-button.png");
-  -moz-image-region: rect(0px, 16px, 16px, 0px);
+  list-style-image: url("chrome://global/skin/icons/closebox.gif");
   -moz-appearance: none;
   border: none !important;
   padding: 2px 0px 0px;
 }
-
-#closeButton > .toolbarbutton-icon {
-  -moz-margin-end: 0px; /* override toolkit's default value */
-}
-
-#closeButton:hover {
-  -moz-image-region: rect(0px, 32px, 16px, 16px);
-}
-
-#closeButton:hover:active {
-  -moz-image-region: rect(0px, 48px, 16px, 32px);
-}