From 8f51d3e1bf09cd14b624bd02c6f16d3c3fbe5c92 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Mon, 25 Oct 2021 23:46:58 +0530 Subject: [PATCH] feat: add `webContents.getPrintersAsync()` (#31023) This deprecates the synchronous and blocking `webContents.getPrinters()` function and introduces `webContents.getPrintersAsync()`, which is asynchronous and non-blocking. Signed-off-by: Darshan Sen --- docs/api/web-contents.md | 10 +++++- lib/browser/api/web-contents.ts | 11 ++++++ shell/browser/api/electron_api_printing.cc | 42 ++++++++++++++++++++-- spec-main/api-web-contents-spec.ts | 10 ++++++ typings/internal-electron.d.ts | 1 + 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 4d8346bd2c72..9a9ffa319fca 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1369,12 +1369,20 @@ Decrease the capturer count by one. The page will be set to hidden or occluded s browser window is hidden or occluded and the capturer count reaches zero. If you want to decrease the hidden capturer count instead you should set `stayHidden` to true. -#### `contents.getPrinters()` +#### `contents.getPrinters()` _Deprecated_ Get the system printer list. Returns [`PrinterInfo[]`](structures/printer-info.md) +**Deprecated:** Should use the new [`contents.getPrintersAsync`](web-contents.md#contentsgetprintersasync) API. + +#### `contents.getPrintersAsync()` + +Get the system printer list. + +Returns `Promise` - Resolves with a [`PrinterInfo[]`](structures/printer-info.md) + #### `contents.print([options], [callback])` * `options` Object (optional) diff --git a/lib/browser/api/web-contents.ts b/lib/browser/api/web-contents.ts index 8bb863a0eb21..fb100e8798d6 100644 --- a/lib/browser/api/web-contents.ts +++ b/lib/browser/api/web-contents.ts @@ -391,6 +391,17 @@ WebContents.prototype.getPrinters = function () { } }; +WebContents.prototype.getPrintersAsync = async function () { + // TODO(nornagon): this API has nothing to do with WebContents and should be + // moved. + if (printing.getPrinterListAsync) { + return printing.getPrinterListAsync(); + } else { + console.error('Error: Printing feature is disabled.'); + return []; + } +}; + WebContents.prototype.loadFile = function (filePath, options = {}) { if (typeof filePath !== 'string') { throw new Error('Must pass filePath as a string'); diff --git a/shell/browser/api/electron_api_printing.cc b/shell/browser/api/electron_api_printing.cc index 6841aec62b3a..75067584b146 100644 --- a/shell/browser/api/electron_api_printing.cc +++ b/shell/browser/api/electron_api_printing.cc @@ -10,7 +10,11 @@ #include "shell/common/node_includes.h" #if BUILDFLAG(ENABLE_PRINTING) +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "printing/backend/print_backend.h" +#include "shell/common/gin_helper/promise.h" +#include "shell/common/process_util.h" #endif namespace gin { @@ -39,13 +43,16 @@ namespace electron { namespace api { #if BUILDFLAG(ENABLE_PRINTING) -printing::PrinterList GetPrinterList() { +printing::PrinterList GetPrinterList(v8::Isolate* isolate) { + EmitWarning(node::Environment::GetCurrent(isolate), + "Deprecation Warning: getPrinters() is deprecated. " + "Use the asynchronous and non-blocking version, " + "getPrintersAsync(), instead.", + "electron"); printing::PrinterList printers; auto print_backend = printing::PrintBackend::CreateInstance( g_browser_process->GetApplicationLocale()); { - // TODO(deepak1556): Deprecate this api in favor of an - // async version and post a non blocing task call. base::ThreadRestrictions::ScopedAllowIO allow_io; printing::mojom::ResultCode code = print_backend->EnumeratePrinters(&printers); @@ -54,6 +61,32 @@ printing::PrinterList GetPrinterList() { } return printers; } + +v8::Local GetPrinterListAsync(v8::Isolate* isolate) { + gin_helper::Promise promise(isolate); + v8::Local handle = promise.GetHandle(); + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, + base::BindOnce([]() { + printing::PrinterList printers; + auto print_backend = printing::PrintBackend::CreateInstance( + g_browser_process->GetApplicationLocale()); + printing::mojom::ResultCode code = + print_backend->EnumeratePrinters(&printers); + if (code != printing::mojom::ResultCode::kSuccess) + LOG(INFO) << "Failed to enumerate printers"; + return printers; + }), + base::BindOnce( + [](gin_helper::Promise promise, + const printing::PrinterList& printers) { + promise.Resolve(printers); + }, + std::move(promise))); + + return handle; +} #endif } // namespace api @@ -64,6 +97,7 @@ namespace { #if BUILDFLAG(ENABLE_PRINTING) using electron::api::GetPrinterList; +using electron::api::GetPrinterListAsync; #endif void Initialize(v8::Local exports, @@ -74,6 +108,8 @@ void Initialize(v8::Local exports, gin_helper::Dictionary dict(isolate, exports); #if BUILDFLAG(ENABLE_PRINTING) dict.SetMethod("getPrinterList", base::BindRepeating(&GetPrinterList)); + dict.SetMethod("getPrinterListAsync", + base::BindRepeating(&GetPrinterListAsync)); #endif } diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index 2de7273c0649..d81e62533907 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -1728,6 +1728,16 @@ describe('webContents module', () => { }); }); + ifdescribe(features.isPrintingEnabled())('getPrintersAsync()', () => { + afterEach(closeAllWindows); + it('can get printer list', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } }); + await w.loadURL('about:blank'); + const printers = await w.webContents.getPrintersAsync(); + expect(printers).to.be.an('array'); + }); + }); + ifdescribe(features.isPrintingEnabled())('printToPDF()', () => { let w: BrowserWindow; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index ab5ea9b55a2a..3a96a650267c 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -71,6 +71,7 @@ declare namespace Electron { _printToPDF(options: any): Promise; _print(options: any, callback?: (success: boolean, failureReason: string) => void): void; _getPrinters(): Electron.PrinterInfo[]; + _getPrintersAsync(): Promise; _init(): void; canGoToIndex(index: number): boolean; getActiveIndex(): number;