зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1657363 - Make nsIPrinterList.printers return a promise. r=jwatt
I intentionally removed the "move the default printer to the front" in windows because that's not a guarantee that we provide in CUPS, but lmk if you want it back. I have zero idea about why the GlobalPrinters code was so ridiculously complex. Depends on D86396 Differential Revision: https://phabricator.services.mozilla.com/D86397
This commit is contained in:
Родитель
b242b603bc
Коммит
2b6c7db4e8
|
@ -14,7 +14,9 @@ async function run() {
|
|||
Ci.nsIPrinterList
|
||||
);
|
||||
|
||||
for await (printer of printerList.printers) {
|
||||
let printers = await printerList.printers;
|
||||
for (let printer of printers) {
|
||||
printer.QueryInterface(Ci.nsIPrinter);
|
||||
info(`Listing basic attributes for ${printer.name}:`);
|
||||
let [supportsDuplex, supportsColor] = await Promise.all([printer.supportsDuplex, printer.supportsColor]);
|
||||
info(`* supportsDuplex: ${supportsDuplex}`);
|
||||
|
|
|
@ -13,11 +13,13 @@ async function run() {
|
|||
let printerList = Cc["@mozilla.org/gfx/printerlist;1"].getService(
|
||||
Ci.nsIPrinterList
|
||||
);
|
||||
if (printerList.printers.length == 0) {
|
||||
let printers = await printerList.printers;
|
||||
if (printers.length == 0) {
|
||||
ok(true, "There were no printers to iterate through.");
|
||||
}
|
||||
|
||||
for (let printer of printerList.printers) {
|
||||
for (let printer of printers) {
|
||||
printer.QueryInterface(Ci.nsIPrinter);
|
||||
isnot(printer.name, null, "Printer name should never be null.");
|
||||
isnot(printer.name, "", "Printer name should never be empty.");
|
||||
info(printer.name);
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_PrintBackgroundTask_h_
|
||||
#define mozilla_PrintBackgroundTask_h_
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
|
||||
// A helper to resolve a DOM Promise with the result of a const method, executed
|
||||
// in another thread.
|
||||
//
|
||||
// Once in the main thread, the caller can turn the result of the method into a
|
||||
// JSValue by specializing ResolveOrReject.
|
||||
namespace mozilla {
|
||||
|
||||
template <typename T, typename Result>
|
||||
void ResolveOrReject(dom::Promise& aPromise, T&, Result& aResult) {
|
||||
aPromise.MaybeResolve(std::forward<Result>(aResult));
|
||||
}
|
||||
|
||||
template <typename T, typename Result, typename... Args>
|
||||
using PrintBackgroundTask = Result (T::*)(Args...) const;
|
||||
|
||||
template <typename T, typename Result, typename... Args>
|
||||
void SpawnPrintBackgroundTask(
|
||||
T& aReceiver, dom::Promise& aPromise,
|
||||
PrintBackgroundTask<T, Result, Args...> aBackgroundTask, Args... aArgs) {
|
||||
auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
|
||||
"nsPrinterBase::SpawnBackgroundTaskPromise", &aPromise);
|
||||
// We actually want to allow to access the printer data from the callback, so
|
||||
// disable strict checking. They should of course only access immutable
|
||||
// members.
|
||||
auto holder = MakeRefPtr<nsMainThreadPtrHolder<T>>(
|
||||
"nsPrinterBase::SpawnBackgroundTaskPrinter", &aReceiver,
|
||||
/* strict = */ false);
|
||||
// See
|
||||
// https://stackoverflow.com/questions/47496358/c-lambdas-how-to-capture-variadic-parameter-pack-from-the-upper-scope
|
||||
// about the tuple shenanigans. It could be improved with C++20
|
||||
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
|
||||
"SpawnPrintBackgroundTask",
|
||||
[holder = std::move(holder), promiseHolder = std::move(promiseHolder),
|
||||
aBackgroundTask, aArgs = std::make_tuple(std::forward<Args>(aArgs)...)] {
|
||||
Result result = std::apply(
|
||||
[&](auto&&... args) {
|
||||
return (holder->get()->*aBackgroundTask)(args...);
|
||||
},
|
||||
std::move(aArgs));
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"SpawnPrintBackgroundTaskResolution",
|
||||
[holder = std::move(holder),
|
||||
promiseHolder = std::move(promiseHolder),
|
||||
result = std::move(result)] {
|
||||
ResolveOrReject(*promiseHolder->get(), *holder->get(), result);
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
// Resolves an async attribute via a background task, creating and storing a
|
||||
// promise as needed in aPromiseSlot.
|
||||
template <typename T, typename Result, typename... Args>
|
||||
nsresult AsyncPromiseAttributeGetter(
|
||||
T& aReceiver, RefPtr<dom::Promise>& aPromiseSlot, JSContext* aCx,
|
||||
dom::Promise** aResultPromise,
|
||||
PrintBackgroundTask<T, Result, Args...> aTask, Args... aArgs) {
|
||||
if (RefPtr<dom::Promise> existing = aPromiseSlot) {
|
||||
existing.forget(aResultPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
aPromiseSlot = dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
|
||||
if (MOZ_UNLIKELY(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
RefPtr<dom::Promise> promise = aPromiseSlot;
|
||||
SpawnPrintBackgroundTask(aReceiver, *promise, aTask,
|
||||
std::forward<Args>(aArgs)...);
|
||||
|
||||
promise.forget(aResultPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -56,7 +56,9 @@ interface nsIPrintSettingsService : nsISupports
|
|||
readonly attribute nsIPrintSettings newPrintSettings;
|
||||
|
||||
/**
|
||||
* The name of the last printer used, or else the system default printer.
|
||||
* The name of the last printer used. Note that this may no longer be a valid
|
||||
* printer anymore, the caller should check and fall back to the system
|
||||
* default printer list otherwise.
|
||||
*/
|
||||
readonly attribute AString lastUsedPrinterName;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ interface nsIPrinterList : nsISupports
|
|||
readonly attribute AString systemDefaultPrinterName;
|
||||
|
||||
/**
|
||||
* The list of printers.
|
||||
* Returns a promise that resolves to an array of printers.
|
||||
*/
|
||||
readonly attribute Array<nsIPrinter> printers;
|
||||
[implicit_jscontext] readonly attribute Promise printers;
|
||||
};
|
||||
|
|
|
@ -890,36 +890,8 @@ nsPrintSettingsService::GetNewPrintSettings(
|
|||
NS_IMETHODIMP
|
||||
nsPrintSettingsService::GetLastUsedPrinterName(
|
||||
nsAString& aLastUsedPrinterName) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrinterList> printerList =
|
||||
do_GetService(NS_PRINTER_LIST_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aLastUsedPrinterName.Truncate();
|
||||
|
||||
// Look up the printer from the last print job
|
||||
nsAutoString lastUsedPrinterName;
|
||||
Preferences::GetString(kPrinterName, lastUsedPrinterName);
|
||||
if (!lastUsedPrinterName.IsEmpty()) {
|
||||
// Verify it's still a valid printer
|
||||
|
||||
nsTArray<RefPtr<nsIPrinter>> printers;
|
||||
rv = printerList->GetPrinters(printers);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
for (nsIPrinter* printer : printers) {
|
||||
nsAutoString printerName;
|
||||
printer->GetName(printerName);
|
||||
if (printerName.Equals(lastUsedPrinterName)) {
|
||||
aLastUsedPrinterName = lastUsedPrinterName;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There is no last printer preference, or it doesn't name a valid printer.
|
||||
// Return the system default from the printer list.
|
||||
printerList->GetSystemDefaultPrinterName(aLastUsedPrinterName);
|
||||
Preferences::GetString(kPrinterName, aLastUsedPrinterName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "nsPaperMargin.h"
|
||||
#include <utility>
|
||||
#include "nsPaper.h"
|
||||
#include "PrintBackgroundTask.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -32,10 +33,7 @@ inline void ImplCycleCollectionUnlink(
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ResolveOrReject(Promise& aPromise, nsPrinterBase&, T& aResult) {
|
||||
aPromise.MaybeResolve(std::forward<T>(aResult));
|
||||
}
|
||||
namespace mozilla {
|
||||
|
||||
template <>
|
||||
void ResolveOrReject(Promise& aPromise, nsPrinterBase&,
|
||||
|
@ -55,86 +53,42 @@ void ResolveOrReject(Promise& aPromise, nsPrinterBase& aPrinter,
|
|||
aPromise.MaybeResolve(result);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void nsPrinterBase::SpawnBackgroundTask(
|
||||
Promise& aPromise, BackgroundTask<T, Args...> aBackgroundTask,
|
||||
Args... aArgs) {
|
||||
auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<Promise>>(
|
||||
"nsPrinterBase::SpawnBackgroundTaskPromise", &aPromise);
|
||||
// We actually want to allow to access the printer data from the callback, so
|
||||
// disable strict checking. They should of course only access immutable
|
||||
// members.
|
||||
auto holder = MakeRefPtr<nsMainThreadPtrHolder<nsPrinterBase>>(
|
||||
"nsPrinterBase::SpawnBackgroundTaskPrinter", this, /* strict = */ false);
|
||||
// See
|
||||
// https://stackoverflow.com/questions/47496358/c-lambdas-how-to-capture-variadic-parameter-pack-from-the-upper-scope
|
||||
// about the tuple shenanigans. It could be improved with C++20
|
||||
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
|
||||
"nsPrinterBase::SpawnBackgroundTask",
|
||||
[holder = std::move(holder), promiseHolder = std::move(promiseHolder),
|
||||
aBackgroundTask, aArgs = std::make_tuple(std::forward<Args>(aArgs)...)] {
|
||||
T result = std::apply(
|
||||
[&](auto&&... args) {
|
||||
return (holder->get()->*aBackgroundTask)(args...);
|
||||
},
|
||||
std::move(aArgs));
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"nsPrinterBase::SpawnBackgroundTaskResolution",
|
||||
[holder = std::move(holder),
|
||||
promiseHolder = std::move(promiseHolder),
|
||||
result = std::move(result)] {
|
||||
ResolveOrReject(*promiseHolder->get(), *holder->get(), result);
|
||||
}));
|
||||
}));
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
template <typename T, typename... Args>
|
||||
nsresult nsPrinterBase::AsyncPromiseAttributeGetter(
|
||||
JSContext* aCx, Promise** aResultPromise, AsyncAttribute aAttribute,
|
||||
BackgroundTask<T, Args...> aBackgroundTask, Args... aArgs) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (RefPtr<Promise> existing = mAsyncAttributePromises[aAttribute]) {
|
||||
existing.forget(aResultPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
ErrorResult rv;
|
||||
mAsyncAttributePromises[aAttribute] =
|
||||
Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
|
||||
if (MOZ_UNLIKELY(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
RefPtr<Promise> promise = mAsyncAttributePromises[aAttribute];
|
||||
SpawnBackgroundTask(*promise, aBackgroundTask, aArgs...);
|
||||
|
||||
promise.forget(aResultPromise);
|
||||
return NS_OK;
|
||||
return mozilla::AsyncPromiseAttributeGetter(
|
||||
*this, mAsyncAttributePromises[aAttribute], aCx, aResultPromise,
|
||||
aBackgroundTask, std::forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrinterBase::GetSupportsDuplex(JSContext* aCx,
|
||||
Promise** aResultPromise) {
|
||||
return AsyncPromiseAttributeGetter<bool>(aCx, aResultPromise,
|
||||
AsyncAttribute::SupportsDuplex,
|
||||
&nsPrinterBase::SupportsDuplex);
|
||||
return AsyncPromiseAttributeGetter(aCx, aResultPromise,
|
||||
AsyncAttribute::SupportsDuplex,
|
||||
&nsPrinterBase::SupportsDuplex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrinterBase::GetSupportsColor(JSContext* aCx,
|
||||
Promise** aResultPromise) {
|
||||
return AsyncPromiseAttributeGetter<bool>(aCx, aResultPromise,
|
||||
AsyncAttribute::SupportsColor,
|
||||
&nsPrinterBase::SupportsColor);
|
||||
return AsyncPromiseAttributeGetter(aCx, aResultPromise,
|
||||
AsyncAttribute::SupportsColor,
|
||||
&nsPrinterBase::SupportsColor);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrinterBase::GetPaperList(JSContext* aCx,
|
||||
Promise** aResultPromise) {
|
||||
return AsyncPromiseAttributeGetter<nsTArray<PaperInfo>>(
|
||||
aCx, aResultPromise, AsyncAttribute::PaperList,
|
||||
&nsPrinterBase::PaperList);
|
||||
return AsyncPromiseAttributeGetter(aCx, aResultPromise,
|
||||
AsyncAttribute::PaperList,
|
||||
&nsPrinterBase::PaperList);
|
||||
}
|
||||
|
||||
void nsPrinterBase::QueryMarginsForPaper(Promise& aPromise, uint64_t aPaperId) {
|
||||
return SpawnBackgroundTask<MarginDouble, uint64_t>(
|
||||
aPromise, &nsPrinterBase::GetMarginsForPaper, aPaperId);
|
||||
return SpawnPrintBackgroundTask(*this, aPromise,
|
||||
&nsPrinterBase::GetMarginsForPaper, aPaperId);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(nsPrinterBase, mAsyncAttributePromises)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "nsIPrinter.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
|
@ -50,12 +51,8 @@ class nsPrinterBase : public nsIPrinter {
|
|||
Last,
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
using BackgroundTask = T (nsPrinterBase::*)(Args...) const;
|
||||
|
||||
// Resolves a promise when a background task finishes.
|
||||
template <typename T, typename... Args>
|
||||
void SpawnBackgroundTask(Promise&, BackgroundTask<T, Args...>, Args... aArgs);
|
||||
template <typename Result, typename... Args>
|
||||
using BackgroundTask = Result (nsPrinterBase::*)(Args...) const;
|
||||
|
||||
// Resolves an async attribute via a background task.
|
||||
template <typename T, typename... Args>
|
||||
|
|
|
@ -9,15 +9,6 @@
|
|||
|
||||
using namespace mozilla;
|
||||
|
||||
nsPrinterCUPS::nsPrinterCUPS(const nsCUPSShim& aShim, cups_dest_t* aPrinter,
|
||||
const nsAString& aDisplayName)
|
||||
: mDisplayName(aDisplayName), mShim(aShim) {
|
||||
MOZ_ASSERT(aPrinter);
|
||||
DebugOnly<const int> numCopied = aShim.cupsCopyDest(aPrinter, 0, &mPrinter);
|
||||
MOZ_ASSERT(numCopied == 1);
|
||||
mPrinterInfo = aShim.cupsCopyDestInfo(CUPS_HTTP_DEFAULT, mPrinter);
|
||||
}
|
||||
|
||||
nsPrinterCUPS::~nsPrinterCUPS() {
|
||||
if (mPrinterInfo) {
|
||||
mShim.cupsFreeDestInfo(mPrinterInfo);
|
||||
|
@ -29,13 +20,6 @@ nsPrinterCUPS::~nsPrinterCUPS() {
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<nsPrinterCUPS> nsPrinterCUPS::Create(
|
||||
const nsCUPSShim& aShim, cups_dest_t* aPrinter,
|
||||
const nsAString& aDisplayName) {
|
||||
return do_AddRef(new nsPrinterCUPS(aShim, aPrinter, aDisplayName));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrinterCUPS::GetName(nsAString& aName) {
|
||||
if (mDisplayName.IsEmpty()) {
|
||||
|
|
|
@ -28,24 +28,21 @@ class nsPrinterCUPS final : public nsPrinterBase {
|
|||
|
||||
nsPrinterCUPS() = delete;
|
||||
|
||||
/**
|
||||
* @p aPrinter must not be null.
|
||||
*/
|
||||
static already_AddRefed<nsPrinterCUPS> Create(
|
||||
const nsCUPSShim& aShim, cups_dest_t* aPrinter,
|
||||
const nsAString& aDisplayname = EmptyString());
|
||||
nsPrinterCUPS(const nsCUPSShim& aShim, nsString aDisplayName,
|
||||
cups_dest_t* aPrinter, cups_dinfo_t* aPrinterInfo)
|
||||
: mShim(aShim),
|
||||
mDisplayName(std::move(aDisplayName)),
|
||||
mPrinter(aPrinter),
|
||||
mPrinterInfo(aPrinterInfo) {}
|
||||
|
||||
private:
|
||||
nsPrinterCUPS(const nsCUPSShim& aShim, cups_dest_t* aPrinter,
|
||||
const nsAString& aDisplayName = EmptyString());
|
||||
|
||||
~nsPrinterCUPS();
|
||||
|
||||
// Little util for getting support flags using the direct CUPS names.
|
||||
bool Supports(const char* option, const char* value) const;
|
||||
|
||||
nsString mDisplayName;
|
||||
const nsCUPSShim& mShim;
|
||||
nsString mDisplayName;
|
||||
cups_dest_t* mPrinter;
|
||||
cups_dinfo_t* mPrinterInfo;
|
||||
};
|
||||
|
|
|
@ -4,8 +4,43 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsPrinterListBase.h"
|
||||
#include "PrintBackgroundTask.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
using mozilla::ErrorResult;
|
||||
using PrinterInfo = nsPrinterListBase::PrinterInfo;
|
||||
|
||||
nsPrinterListBase::nsPrinterListBase() = default;
|
||||
nsPrinterListBase::~nsPrinterListBase() = default;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPrinterListBase, nsIPrinterList)
|
||||
NS_IMPL_CYCLE_COLLECTION(nsPrinterListBase, mPrintersPromise)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterListBase)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPrinterList)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrinterList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterListBase)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterListBase)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template <>
|
||||
void ResolveOrReject(dom::Promise& aPromise, nsPrinterListBase& aList,
|
||||
const nsTArray<PrinterInfo>& aInfo) {
|
||||
nsTArray<RefPtr<nsIPrinter>> printers;
|
||||
printers.SetCapacity(aInfo.Length());
|
||||
for (auto& info : aInfo) {
|
||||
printers.AppendElement(aList.CreatePrinter(info));
|
||||
}
|
||||
aPromise.MaybeResolve(printers);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
NS_IMETHODIMP nsPrinterListBase::GetPrinters(JSContext* aCx,
|
||||
Promise** aResult) {
|
||||
return mozilla::AsyncPromiseAttributeGetter(
|
||||
*this, mPrintersPromise, aCx, aResult, &nsPrinterListBase::GetPrinters);
|
||||
}
|
||||
|
|
|
@ -7,11 +7,33 @@
|
|||
#define nsPrinterListBase_h__
|
||||
|
||||
#include "nsIPrinterList.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsPrinterListBase : public nsIPrinterList {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
using Promise = mozilla::dom::Promise;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsPrinterListBase)
|
||||
NS_IMETHOD GetPrinters(JSContext*, Promise**) final;
|
||||
|
||||
struct PrinterInfo {
|
||||
// Both windows and CUPS: The name of the printer.
|
||||
nsString mName;
|
||||
// CUPS only: Two handles to owned cups_dest_t / cups_dinfo_t objects.
|
||||
std::array<void*, 2> mCupsHandles{};
|
||||
};
|
||||
|
||||
// Called off the main thread, collect information to create an appropriate
|
||||
// list of printers.
|
||||
virtual nsTArray<PrinterInfo> GetPrinters() const = 0;
|
||||
|
||||
// Create an nsIPrinter object given the information we obtained from the
|
||||
// background thread.
|
||||
virtual RefPtr<nsIPrinter> CreatePrinter(PrinterInfo) const = 0;
|
||||
|
||||
// No copy or move, we're an identity.
|
||||
nsPrinterListBase(const nsPrinterListBase&) = delete;
|
||||
|
@ -20,6 +42,8 @@ class nsPrinterListBase : public nsIPrinterList {
|
|||
protected:
|
||||
nsPrinterListBase();
|
||||
virtual ~nsPrinterListBase();
|
||||
|
||||
RefPtr<Promise> mPrintersPromise;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,34 +11,52 @@
|
|||
#include "prenv.h"
|
||||
|
||||
static nsCUPSShim sCupsShim;
|
||||
using PrinterInfo = nsPrinterListBase::PrinterInfo;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrinterListCUPS::GetPrinters(nsTArray<RefPtr<nsIPrinter>>& aPrinters) {
|
||||
nsTArray<PrinterInfo> nsPrinterListCUPS::GetPrinters() const {
|
||||
if (!sCupsShim.EnsureInitialized()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return {};
|
||||
}
|
||||
|
||||
nsTArray<PrinterInfo> printerInfoList;
|
||||
|
||||
cups_dest_t* printers = nullptr;
|
||||
auto numPrinters = sCupsShim.cupsGetDests(&printers);
|
||||
aPrinters.SetCapacity(numPrinters);
|
||||
printerInfoList.SetCapacity(numPrinters);
|
||||
|
||||
for (auto i : mozilla::IntegerRange(0, numPrinters)) {
|
||||
cups_dest_t* dest = printers + i;
|
||||
|
||||
nsString displayName;
|
||||
GetDisplayNameForPrinter(*dest, displayName);
|
||||
RefPtr<nsPrinterCUPS> cupsPrinter =
|
||||
nsPrinterCUPS::Create(sCupsShim, dest, displayName);
|
||||
cups_dest_t* ownedDest = nullptr;
|
||||
mozilla::DebugOnly<const int> numCopied =
|
||||
sCupsShim.cupsCopyDest(dest, 0, &ownedDest);
|
||||
MOZ_ASSERT(numCopied == 1);
|
||||
|
||||
aPrinters.AppendElement(cupsPrinter);
|
||||
cups_dinfo_t* ownedInfo =
|
||||
sCupsShim.cupsCopyDestInfo(CUPS_HTTP_DEFAULT, ownedDest);
|
||||
|
||||
nsString name;
|
||||
GetDisplayNameForPrinter(*dest, name);
|
||||
|
||||
printerInfoList.AppendElement(
|
||||
PrinterInfo{std::move(name), {ownedDest, ownedInfo}});
|
||||
}
|
||||
|
||||
sCupsShim.cupsFreeDests(numPrinters, printers);
|
||||
return NS_OK;
|
||||
return printerInfoList;
|
||||
}
|
||||
|
||||
RefPtr<nsIPrinter> nsPrinterListCUPS::CreatePrinter(PrinterInfo aInfo) const {
|
||||
return mozilla::MakeRefPtr<nsPrinterCUPS>(
|
||||
sCupsShim, std::move(aInfo.mName),
|
||||
static_cast<cups_dest_t*>(aInfo.mCupsHandles[0]),
|
||||
static_cast<cups_dinfo_t*>(aInfo.mCupsHandles[1]));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrinterListCUPS::GetSystemDefaultPrinterName(nsAString& aName) {
|
||||
aName.Truncate();
|
||||
|
||||
if (!sCupsShim.EnsureInitialized()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -48,7 +66,7 @@ nsPrinterListCUPS::GetSystemDefaultPrinterName(nsAString& aName) {
|
|||
sCupsShim.cupsGetNamedDest(CUPS_HTTP_DEFAULT, /* name */ nullptr,
|
||||
/* instance */ nullptr);
|
||||
if (!dest) {
|
||||
return NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GetDisplayNameForPrinter(*dest, aName);
|
||||
|
|
|
@ -12,7 +12,12 @@
|
|||
struct cups_dest_s;
|
||||
|
||||
class nsPrinterListCUPS final : public nsPrinterListBase {
|
||||
NS_DECL_NSIPRINTERLIST
|
||||
NS_IMETHOD InitPrintSettingsFromPrinter(const nsAString&,
|
||||
nsIPrintSettings*) final;
|
||||
NS_IMETHOD GetSystemDefaultPrinterName(nsAString&) final;
|
||||
|
||||
nsTArray<PrinterInfo> GetPrinters() const final;
|
||||
RefPtr<nsIPrinter> CreatePrinter(PrinterInfo) const final;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// This is implemented in nsDeviceContextSpecX. We could add a new class to
|
||||
|
|
|
@ -55,45 +55,8 @@ using namespace mozilla::widget;
|
|||
static const wchar_t kDriverName[] = L"WINSPOOL";
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// The printer data is shared between the PrinterList and the
|
||||
// nsDeviceContextSpecWin The PrinterList creates the printer info but the
|
||||
// nsDeviceContextSpecWin cleans it up If it gets created (via the Page Setup
|
||||
// Dialog) but the user never prints anything then it will never be delete, so
|
||||
// this class takes care of that.
|
||||
class GlobalPrinters {
|
||||
public:
|
||||
static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
|
||||
~GlobalPrinters() { FreeGlobalPrinters(); }
|
||||
|
||||
void FreeGlobalPrinters();
|
||||
|
||||
bool PrintersAreAllocated() { return mPrinters != nullptr; }
|
||||
LPWSTR GetItemFromList(int32_t aInx) {
|
||||
return mPrinters ? mPrinters->ElementAt(aInx) : nullptr;
|
||||
}
|
||||
nsresult EnumeratePrinterList();
|
||||
void GetDefaultPrinterName(nsAString& aDefaultPrinterName);
|
||||
uint32_t GetNumPrinters() { return mPrinters ? mPrinters->Length() : 0; }
|
||||
|
||||
protected:
|
||||
GlobalPrinters() {}
|
||||
nsresult EnumerateNativePrinters();
|
||||
void ReallocatePrinters();
|
||||
|
||||
static GlobalPrinters mGlobalPrinters;
|
||||
static nsTArray<LPWSTR>* mPrinters;
|
||||
};
|
||||
//---------------
|
||||
// static members
|
||||
GlobalPrinters GlobalPrinters::mGlobalPrinters;
|
||||
nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
|
||||
|
||||
struct AutoFreeGlobalPrinters {
|
||||
~AutoFreeGlobalPrinters() {
|
||||
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
nsDeviceContextSpecWin::nsDeviceContextSpecWin()
|
||||
: mDevMode(nullptr)
|
||||
|
@ -111,15 +74,33 @@ NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
|
|||
nsDeviceContextSpecWin::~nsDeviceContextSpecWin() {
|
||||
SetDevMode(nullptr);
|
||||
|
||||
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
|
||||
if (psWin) {
|
||||
psWin->SetDeviceName(EmptyString());
|
||||
psWin->SetDriverName(EmptyString());
|
||||
psWin->SetDevMode(nullptr);
|
||||
if (nsCOMPtr<nsIPrintSettingsWin> ps = do_QueryInterface(mPrintSettings)) {
|
||||
ps->SetDeviceName(EmptyString());
|
||||
ps->SetDriverName(EmptyString());
|
||||
ps->SetDevMode(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void GetDefaultPrinterName(nsAString& aDefaultPrinterName) {
|
||||
aDefaultPrinterName.Truncate();
|
||||
|
||||
DWORD length = 0;
|
||||
GetDefaultPrinterW(nullptr, &length);
|
||||
|
||||
if (length) {
|
||||
aDefaultPrinterName.SetLength(length);
|
||||
if (GetDefaultPrinterW((LPWSTR)aDefaultPrinterName.BeginWriting(),
|
||||
&length)) {
|
||||
// `length` includes the terminating null, so we subtract that from our
|
||||
// string length.
|
||||
aDefaultPrinterName.SetLength(length - 1);
|
||||
} else {
|
||||
aDefaultPrinterName.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
// Free them, we won't need them for a while
|
||||
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
||||
PR_PL(("DEFAULT PRINTER [%s]\n",
|
||||
NS_ConvertUTF16toUTF8(aDefaultPrinterName).get()));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
@ -137,7 +118,7 @@ NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
|
|||
|
||||
// If there is no name then use the default printer
|
||||
if (printerName.IsEmpty()) {
|
||||
GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
|
||||
GetDefaultPrinterName(printerName);
|
||||
}
|
||||
|
||||
// Gather telemetry on the print target type.
|
||||
|
@ -415,17 +396,6 @@ nsresult nsDeviceContextSpecWin::GetDataFromPrinter(const nsAString& aName,
|
|||
nsIPrintSettings* aPS) {
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
|
||||
rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
|
||||
if (NS_FAILED(rv)) {
|
||||
PR_PL(
|
||||
("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't "
|
||||
"retrieve printers!\n"));
|
||||
DISPLAY_LAST_ERROR
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsHPRINTER hPrinter = nullptr;
|
||||
const nsString& flat = PromiseFlatString(aName);
|
||||
wchar_t* name =
|
||||
|
@ -512,13 +482,55 @@ nsresult nsDeviceContextSpecWin::GetDataFromPrinter(const nsAString& aName,
|
|||
// Printer List
|
||||
//***********************************************************
|
||||
|
||||
nsPrinterListWin::~nsPrinterListWin() {
|
||||
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
||||
nsPrinterListWin::~nsPrinterListWin() = default;
|
||||
|
||||
nsTArray<nsPrinterListBase::PrinterInfo> nsPrinterListWin::GetPrinters() const {
|
||||
PR_PL(("EnumerateNativePrinters\n"));
|
||||
|
||||
const DWORD kLevel = 4;
|
||||
using RecType = PRINTER_INFO_4;
|
||||
|
||||
DWORD needed = 0;
|
||||
DWORD count = 0;
|
||||
const DWORD kFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
|
||||
BOOL ok = EnumPrinters(kFlags,
|
||||
nullptr, // Name
|
||||
kLevel, // Level
|
||||
nullptr, // pPrinterEnum
|
||||
0, // cbBuf (buffer size)
|
||||
&needed, // Bytes needed in buffer
|
||||
&count);
|
||||
|
||||
AutoTArray<BYTE, 1024> buffer;
|
||||
if (needed > 0) {
|
||||
buffer.SetLength(needed);
|
||||
ok = EnumPrinters(kFlags, nullptr, kLevel, buffer.Elements(),
|
||||
buffer.Length(), &needed, &count);
|
||||
}
|
||||
|
||||
if (!ok || !count) {
|
||||
PR_PL(("[No printers found]\n"));
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* printers = reinterpret_cast<const RecType*>(buffer.Elements());
|
||||
nsTArray<PrinterInfo> list;
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
list.AppendElement(PrinterInfo{nsString(printers[i].pPrinterName)});
|
||||
PR_PL(("Printer Name: %s\n",
|
||||
NS_ConvertUTF16toUTF8(printers[i].pPrinterName).get()));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
RefPtr<nsIPrinter> nsPrinterListWin::CreatePrinter(PrinterInfo aInfo) const {
|
||||
return nsPrinterWin::Create(std::move(aInfo.mName));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrinterListWin::GetSystemDefaultPrinterName(nsAString& aName) {
|
||||
GlobalPrinters::GetInstance()->GetDefaultPrinterName(aName);
|
||||
GetDefaultPrinterName(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -541,12 +553,6 @@ nsPrinterListWin::InitPrintSettingsFromPrinter(
|
|||
RefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
|
||||
if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
AutoFreeGlobalPrinters autoFreeGlobalPrinters;
|
||||
|
||||
// If the settings have already been initialized from prefs then pass these to
|
||||
// GetDataFromPrinter, so that they are saved to the printer.
|
||||
bool initializedFromPrefs;
|
||||
|
@ -586,164 +592,3 @@ nsPrinterListWin::InitPrintSettingsFromPrinter(
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrinterListWin::GetPrinters(nsTArray<RefPtr<nsIPrinter>>& aPrinters) {
|
||||
nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
|
||||
if (NS_FAILED(rv)) {
|
||||
PR_PL(
|
||||
("***** nsDeviceContextSpecWin::GetPrinters - Couldn't "
|
||||
"retrieve printers!\n"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
|
||||
for (uint32_t printerInx = 0; printerInx < numPrinters; ++printerInx) {
|
||||
// wchar_t (used in LPWSTR) is 16 bits on Windows.
|
||||
// https://docs.microsoft.com/en-us/cpp/cpp/char-wchar-t-char16-t-char32-t?view=vs-2019
|
||||
LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx);
|
||||
|
||||
nsAutoString printerName(name);
|
||||
if (RefPtr<nsPrinterWin> printer = nsPrinterWin::Create(printerName)) {
|
||||
aPrinters.AppendElement(printer.forget());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
//-- Global Printers
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// THe array hold the name and port for each printer
|
||||
void GlobalPrinters::ReallocatePrinters() {
|
||||
if (PrintersAreAllocated()) {
|
||||
FreeGlobalPrinters();
|
||||
}
|
||||
mPrinters = new nsTArray<LPWSTR>();
|
||||
NS_ASSERTION(mPrinters, "Printers Array is NULL!");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void GlobalPrinters::FreeGlobalPrinters() {
|
||||
if (mPrinters != nullptr) {
|
||||
for (uint32_t i = 0; i < mPrinters->Length(); i++) {
|
||||
free(mPrinters->ElementAt(i));
|
||||
}
|
||||
delete mPrinters;
|
||||
mPrinters = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
nsresult GlobalPrinters::EnumerateNativePrinters() {
|
||||
nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
|
||||
PR_PL(("-----------------------\n"));
|
||||
PR_PL(("EnumerateNativePrinters\n"));
|
||||
|
||||
const DWORD kLevel = 4;
|
||||
using RecType = PRINTER_INFO_4;
|
||||
|
||||
DWORD needed = 0;
|
||||
DWORD count = 0;
|
||||
const DWORD kFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
|
||||
BOOL ok = EnumPrinters(kFlags,
|
||||
nullptr, // Name
|
||||
kLevel, // Level
|
||||
nullptr, // pPrinterEnum
|
||||
0, // cbBuf (buffer size)
|
||||
&needed, // Bytes needed in buffer
|
||||
&count);
|
||||
|
||||
AutoTArray<BYTE, 1024> buffer;
|
||||
if (needed > 0) {
|
||||
buffer.SetLength(needed);
|
||||
ok = EnumPrinters(kFlags, nullptr, kLevel, buffer.Elements(),
|
||||
buffer.Length(), &needed, &count);
|
||||
}
|
||||
|
||||
if (ok && count) {
|
||||
const RecType* printers =
|
||||
reinterpret_cast<const RecType*>(buffer.Elements());
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
mPrinters->AppendElement(wcsdup(printers[i].pPrinterName));
|
||||
PR_PL(("Printer Name: %s\n",
|
||||
NS_ConvertUTF16toUTF8(printers[i].pPrinterName).get()));
|
||||
}
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
PR_PL(("[No printers found]\n"));
|
||||
}
|
||||
|
||||
PR_PL(("-----------------------\n"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Uses the GetProfileString to get the default printer from the registry
|
||||
void GlobalPrinters::GetDefaultPrinterName(nsAString& aDefaultPrinterName) {
|
||||
aDefaultPrinterName.Truncate();
|
||||
|
||||
DWORD length = 0;
|
||||
GetDefaultPrinterW(nullptr, &length);
|
||||
|
||||
if (length) {
|
||||
aDefaultPrinterName.SetLength(length);
|
||||
if (GetDefaultPrinterW((LPWSTR)aDefaultPrinterName.BeginWriting(),
|
||||
&length)) {
|
||||
// `length` includes the terminating null, so we subtract that from our
|
||||
// string length.
|
||||
aDefaultPrinterName.SetLength(length - 1);
|
||||
} else {
|
||||
aDefaultPrinterName.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
PR_PL(("DEFAULT PRINTER [%s]\n",
|
||||
NS_ConvertUTF16toUTF8(aDefaultPrinterName).get()));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// This goes and gets the list of available printers and puts
|
||||
// the default printer at the beginning of the list
|
||||
nsresult GlobalPrinters::EnumeratePrinterList() {
|
||||
// reallocate and get a new list each time it is asked for
|
||||
// this deletes the list and re-allocates them
|
||||
ReallocatePrinters();
|
||||
|
||||
// any of these could only fail with an OUT_MEMORY_ERROR
|
||||
// PRINTER_ENUM_LOCAL should get the network printers on Win95
|
||||
nsresult rv = EnumerateNativePrinters();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get the name of the default printer
|
||||
nsAutoString defPrinterName;
|
||||
GetDefaultPrinterName(defPrinterName);
|
||||
|
||||
// put the default printer at the beginning of list
|
||||
if (!defPrinterName.IsEmpty()) {
|
||||
for (uint32_t i = 0; i < mPrinters->Length(); i++) {
|
||||
LPWSTR name = mPrinters->ElementAt(i);
|
||||
if (defPrinterName.Equals(name)) {
|
||||
if (i > 0) {
|
||||
LPWSTR ptr = mPrinters->ElementAt(0);
|
||||
mPrinters->ElementAt(0) = name;
|
||||
mPrinters->ElementAt(i) = ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we at least tried to get the printers
|
||||
if (!PrintersAreAllocated()) {
|
||||
PR_PL(
|
||||
("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t "
|
||||
"allocated\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -85,7 +85,13 @@ class nsDeviceContextSpecWin : public nsIDeviceContextSpec {
|
|||
//-------------------------------------------------------------------------
|
||||
class nsPrinterListWin final : public nsPrinterListBase {
|
||||
public:
|
||||
NS_DECL_NSIPRINTERLIST
|
||||
NS_IMETHOD InitPrintSettingsFromPrinter(const nsAString&,
|
||||
nsIPrintSettings*) final;
|
||||
NS_IMETHOD GetSystemDefaultPrinterName(nsAString&) final;
|
||||
|
||||
nsTArray<PrinterInfo> GetPrinters() const final;
|
||||
RefPtr<nsIPrinter> CreatePrinter(PrinterInfo) const final;
|
||||
|
||||
nsPrinterListWin() = default;
|
||||
|
||||
private:
|
||||
|
|
Загрузка…
Ссылка в новой задаче