Bug 909760 - Show download progress in the MacOS Finder r=spohl,mak

Show download progress in the MacOS Finder

Differential Revision: https://phabricator.services.mozilla.com/D30688

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Christoph Walcher 2019-06-19 18:48:49 +00:00
parent c69f589086
commit cf2e11f3c2
10 changed files with 267 additions and 0 deletions

View File

@ -1946,6 +1946,10 @@ var gBrowserInit = {
DownloadsCommon.initializeAllDataLinks();
ChromeUtils.import("resource:///modules/DownloadsTaskbar.jsm", {})
.DownloadsTaskbar.registerIndicator(window);
if (AppConstants.platform == "macosx") {
ChromeUtils.import("resource:///modules/DownloadsMacFinderProgress.jsm")
.DownloadsMacFinderProgress.register();
}
} catch (ex) {
Cu.reportError(ex);
}

View File

@ -0,0 +1,87 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
/* 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/. */
/**
* Handles the download progress indicator of the macOS Finder.
*/
"use strict";
var EXPORTED_SYMBOLS = [
"DownloadsMacFinderProgress",
];
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
Downloads: "resource://gre/modules/Downloads.jsm",
});
var DownloadsMacFinderProgress = {
/**
* Maps the path of the download, to the according progress indicator instance.
*/
_finderProgresses: null,
/**
* This method is called after a new browser window on macOS is opened, it
* registers for receiving download events for the progressbar of the Finder.
*/
register() {
// Ensure to register only once per process and not for every window.
if (!this._finderProgresses) {
this._finderProgresses = new Map();
Downloads.getList(Downloads.ALL).then(list => list.addView(this));
}
},
onDownloadAdded(download) {
if (download.stopped) {
return;
}
let finderProgress = Cc["@mozilla.org/widget/macfinderprogress;1"]
.createInstance(Ci.nsIMacFinderProgress);
let path = download.target.path;
finderProgress.init(path, () => {
download.cancel().catch(Cu.reportError);
download.removePartialData().catch(Cu.reportError);
});
if (download.hasProgress) {
finderProgress.updateProgress(download.currentBytes, download.totalBytes);
} else {
finderProgress.updateProgress(0, 0);
}
this._finderProgresses.set(path, finderProgress);
},
onDownloadChanged(download) {
let path = download.target.path;
let finderProgress = this._finderProgresses.get(path);
if (!finderProgress) {
// The download is not tracked, it may have been restarted,
// thus forward the call to onDownloadAdded to check if it should be tracked.
this.onDownloadAdded(download);
} else if (download.stopped) {
finderProgress.end();
this._finderProgresses.delete(path);
} else {
finderProgress.updateProgress(download.currentBytes, download.totalBytes);
}
},
onDownloadRemoved(download) {
let path = download.target.path;
let finderProgress = this._finderProgresses.get(path);
if (finderProgress) {
finderProgress.end();
this._finderProgresses.delete(path);
}
},
};

View File

@ -18,5 +18,10 @@ EXTRA_JS_MODULES += [
'DownloadsViewUI.jsm',
]
toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
if toolkit == 'cocoa':
EXTRA_JS_MODULES += ['DownloadsMacFinderProgress.jsm']
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Downloads Panel')

View File

@ -39,6 +39,7 @@ UNIFIED_SOURCES += [
'nsLookAndFeel.mm',
'nsMacCursor.mm',
'nsMacDockSupport.mm',
'nsMacFinderProgress.mm',
'nsMacSharingService.mm',
'nsMacWebAppUtils.mm',
'nsMenuBarX.mm',

View File

@ -0,0 +1,24 @@
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
/* 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 _MACFINDERPROGRESS_H_
#define _MACFINDERPROGRESS_H_
#include "nsIMacFinderProgress.h"
#include "nsCOMPtr.h"
class nsMacFinderProgress : public nsIMacFinderProgress {
public:
nsMacFinderProgress();
NS_DECL_ISUPPORTS
NS_DECL_NSIMACFINDERPROGRESS
protected:
virtual ~nsMacFinderProgress();
NSProgress* mProgress;
};
#endif

View File

@ -0,0 +1,88 @@
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#import <Cocoa/Cocoa.h>
#include "nsMacFinderProgress.h"
#include "nsThreadUtils.h"
#include "nsString.h"
#include "nsObjCExceptions.h"
NS_IMPL_ISUPPORTS(nsMacFinderProgress, nsIMacFinderProgress)
nsMacFinderProgress::nsMacFinderProgress() : mProgress(nil) {}
nsMacFinderProgress::~nsMacFinderProgress() {
if (mProgress) {
[mProgress.cancellationHandler release];
[mProgress release];
}
}
NS_IMETHODIMP
nsMacFinderProgress::Init(const nsAString& path,
nsIMacFinderProgressCanceledCallback* cancellationCallback) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NSURL* pathUrl = [NSURL
fileURLWithPath:[NSString
stringWithCharacters:reinterpret_cast<const unichar*>(path.BeginReading())
length:path.Length()]];
NSDictionary* userInfo = @{
@"NSProgressFileOperationKindKey" : @"NSProgressFileOperationKindDownloading",
@"NSProgressFileURLKey" : pathUrl
};
mProgress = [[NSProgress alloc] initWithParent:nil userInfo:userInfo];
mProgress.kind = NSProgressKindFile;
mProgress.cancellable = YES;
nsMainThreadPtrHandle<nsIMacFinderProgressCanceledCallback> cancellationCallbackHandle(
new nsMainThreadPtrHolder<nsIMacFinderProgressCanceledCallback>(
"MacFinderProgress::CancellationCallback", cancellationCallback));
mProgress.cancellationHandler = ^{
NS_DispatchToMainThread(
NS_NewRunnableFunction("MacFinderProgress::Canceled", [cancellationCallbackHandle] {
MOZ_ASSERT(NS_IsMainThread());
cancellationCallbackHandle->Canceled();
}));
};
[mProgress publish];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsMacFinderProgress::UpdateProgress(uint64_t currentProgress, uint64_t totalProgress) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if (mProgress) {
mProgress.totalUnitCount = totalProgress;
mProgress.completedUnitCount = currentProgress;
}
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsMacFinderProgress::End() {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if (mProgress) {
[mProgress unpublish];
[mProgress release];
mProgress = nil;
}
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}

View File

@ -82,6 +82,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsNativeMenuServiceX)
#include "nsMacDockSupport.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacDockSupport)
#include "nsMacFinderProgress.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacFinderProgress)
#include "nsMacSharingService.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacSharingService)
@ -123,6 +126,7 @@ NS_DEFINE_NAMED_CID(NS_IDLE_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_SYSTEMALERTSSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_NATIVEMENUSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_MACDOCKSUPPORT_CID);
NS_DEFINE_NAMED_CID(NS_MACFINDERPROGRESS_CID);
NS_DEFINE_NAMED_CID(NS_MACSHARINGSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_MACWEBAPPUTILS_CID);
NS_DEFINE_NAMED_CID(NS_STANDALONENATIVEMENU_CID);
@ -153,6 +157,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
{&kNS_SYSTEMALERTSSERVICE_CID, false, NULL, OSXNotificationCenterConstructor},
{&kNS_NATIVEMENUSERVICE_CID, false, NULL, nsNativeMenuServiceXConstructor},
{&kNS_MACDOCKSUPPORT_CID, false, NULL, nsMacDockSupportConstructor},
{&kNS_MACFINDERPROGRESS_CID, false, NULL, nsMacFinderProgressConstructor},
{&kNS_MACSHARINGSERVICE_CID, false, NULL, nsMacSharingServiceConstructor},
{&kNS_MACWEBAPPUTILS_CID, false, NULL, nsMacWebAppUtilsConstructor},
{&kNS_STANDALONENATIVEMENU_CID, false, NULL, nsStandaloneNativeMenuConstructor},
@ -182,6 +187,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
{"@mozilla.org/system-alerts-service;1", &kNS_SYSTEMALERTSSERVICE_CID},
{"@mozilla.org/widget/nativemenuservice;1", &kNS_NATIVEMENUSERVICE_CID},
{"@mozilla.org/widget/macdocksupport;1", &kNS_MACDOCKSUPPORT_CID},
{"@mozilla.org/widget/macfinderprogress;1", &kNS_MACFINDERPROGRESS_CID},
{"@mozilla.org/widget/macsharingservice;1", &kNS_MACSHARINGSERVICE_CID},
{"@mozilla.org/widget/mac-web-app-utils;1", &kNS_MACWEBAPPUTILS_CID},
{"@mozilla.org/widget/standalonenativemenu;1", &kNS_STANDALONENATIVEMENU_CID},

View File

@ -59,6 +59,7 @@ if toolkit == 'windows':
elif toolkit == 'cocoa':
XPIDL_SOURCES += [
'nsIMacDockSupport.idl',
'nsIMacFinderProgress.idl',
'nsIMacSharingService.idl',
'nsIMacWebAppUtils.idl',
'nsIStandaloneNativeMenu.idl',

View File

@ -0,0 +1,43 @@
/* -*- 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 "nsISupports.idl"
[scriptable, function, uuid(6BAE6D1C-7FFD-4354-8D7B-64697E98A801)]
interface nsIMacFinderProgressCanceledCallback : nsISupports
{
void canceled();
};
[scriptable, uuid(25A0B01F-54D4-4AEF-B2BF-C5764CDC68A8)]
interface nsIMacFinderProgress : nsISupports
{
/**
* Initialize and display a new Finder progressbar on the given file
*
* @param path The path of the file
*
* @param canceledCallback Callback which is called when cancelation is requested
*/
void init(in AString path, in nsIMacFinderProgressCanceledCallback canceledCallback);
/**
* Update the current and total progess. If currentProgress and totalProgress are both 0,
* the progress is indetermined
*
* @param currentProgress The current progress
*
* @param totalProgress The total progress
*/
void updateProgress(in unsigned long long currentProgress, in unsigned long long totalProgress);
/**
* End displaying the progressbar on the file
*/
void end();
};

View File

@ -90,6 +90,14 @@
} \
}
// {74EA4101-A5BB-49BC-9984-66DA8B225A37}
#define NS_MACFINDERPROGRESS_CID \
{ \
0x74EA4101, 0xA5BB, 0x49BC, { \
0x99, 0x84, 0x66, 0xDA, 0x8B, 0x22, 0x5A, 0x37 \
} \
}
// {de59fe1a-46c8-490f-b04d-34545acb06c9}
#define NS_MACSHARINGSERVICE_CID \
{ \