Bug 1698786: part 1) Add some logging to `mozInlineSpellChecker`. r=masayuki
[gecko.git] / widget / nsPrinterListCUPS.cpp
blobb1d6957526522e556617db74143cd7da579f6ef5
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsPrinterListCUPS.h"
7 #include "mozilla/IntegerRange.h"
8 #include "mozilla/Maybe.h"
9 #include "nsCUPSShim.h"
10 #include "nsPrinterCUPS.h"
11 #include "nsString.h"
12 #include "prenv.h"
14 // Use a local static to initialize the CUPS shim lazily, when it's needed.
15 // This is used in order to avoid a global constructor.
16 static nsCUPSShim& CupsShim() {
17 static nsCUPSShim sCupsShim;
18 return sCupsShim;
21 using PrinterInfo = nsPrinterListBase::PrinterInfo;
23 /**
24 * Retrieves a human-readable name for the printer from CUPS.
25 * https://www.cups.org/doc/cupspm.html#basic-destination-information
27 static void GetDisplayNameForPrinter(const cups_dest_t& aDest,
28 nsAString& aName) {
29 // macOS clients expect prettified printer names
30 // while GTK clients expect non-prettified names.
31 // If you change this, please change NamedPrinter accordingly.
32 #ifdef XP_MACOSX
33 const char* displayName = CupsShim().cupsGetOption(
34 "printer-info", aDest.num_options, aDest.options);
35 if (displayName) {
36 CopyUTF8toUTF16(MakeStringSpan(displayName), aName);
38 #endif
41 NS_IMETHODIMP
42 nsPrinterListCUPS::InitPrintSettingsFromPrinter(
43 const nsAString& aPrinterName, nsIPrintSettings* aPrintSettings) {
44 MOZ_ASSERT(aPrintSettings);
46 // Set a default file name.
47 nsAutoString filename;
48 nsresult rv = aPrintSettings->GetToFileName(filename);
49 if (NS_FAILED(rv) || filename.IsEmpty()) {
50 const char* path = PR_GetEnv("PWD");
51 if (!path) {
52 path = PR_GetEnv("HOME");
55 if (path) {
56 CopyUTF8toUTF16(mozilla::MakeStringSpan(path), filename);
57 filename.AppendLiteral("/mozilla.pdf");
58 } else {
59 filename.AssignLiteral("mozilla.pdf");
62 aPrintSettings->SetToFileName(filename);
65 aPrintSettings->SetIsInitializedFromPrinter(true);
66 return NS_OK;
69 static int CupsDestCallback(void* user_data, unsigned aFlags,
70 cups_dest_t* aDest) {
71 MOZ_ASSERT(user_data);
72 nsTArray<PrinterInfo>* printerInfoList =
73 reinterpret_cast<nsTArray<PrinterInfo>*>(user_data);
75 cups_dest_t* ownedDest = nullptr;
76 mozilla::DebugOnly<const int> numCopied =
77 CupsShim().cupsCopyDest(aDest, 0, &ownedDest);
78 MOZ_ASSERT(numCopied == 1);
80 nsString name;
81 GetDisplayNameForPrinter(*aDest, name);
83 printerInfoList->AppendElement(PrinterInfo{std::move(name), ownedDest});
85 return aFlags == CUPS_DEST_FLAGS_MORE ? 1 : 0;
88 nsTArray<PrinterInfo> nsPrinterListCUPS::Printers() const {
89 if (!CupsShim().InitOkay()) {
90 return {};
93 nsTArray<PrinterInfo> printerInfoList;
94 if (!CupsShim().cupsEnumDests(
95 CUPS_DEST_FLAGS_NONE,
96 0 /* timeout, 0 timeout shouldn't be a problem since we are masking
97 CUPS_PRINTER_DISCOVERED */
99 nullptr /* cancel* */, CUPS_PRINTER_LOCAL,
100 CUPS_PRINTER_FAX | CUPS_PRINTER_SCANNER | CUPS_PRINTER_DISCOVERED,
101 &CupsDestCallback, &printerInfoList)) {
102 return {};
105 return printerInfoList;
108 RefPtr<nsIPrinter> nsPrinterListCUPS::CreatePrinter(PrinterInfo aInfo) const {
109 return mozilla::MakeRefPtr<nsPrinterCUPS>(
110 mCommonPaperInfo, CupsShim(), std::move(aInfo.mName),
111 static_cast<cups_dest_t*>(aInfo.mCupsHandle));
114 mozilla::Maybe<PrinterInfo> nsPrinterListCUPS::PrinterByName(
115 nsString aPrinterName) const {
116 mozilla::Maybe<PrinterInfo> rv;
117 if (!CupsShim().InitOkay()) {
118 return rv;
121 // Will contain the printer, if found. This must be fully owned, and not a
122 // member of another array of printers.
123 cups_dest_t* printer = nullptr;
125 #ifdef XP_MACOSX
126 // On OS X the printer name given to this function is the readable/display
127 // name and not the CUPS name, so we iterate over all the printers for now.
128 // See bug 1659807 for one approach to improve perf here.
130 nsAutoCString printerName;
131 CopyUTF16toUTF8(aPrinterName, printerName);
132 cups_dest_t* printers = nullptr;
133 const auto numPrinters = CupsShim().cupsGetDests(&printers);
134 for (auto i : mozilla::IntegerRange(0, numPrinters)) {
135 const char* const displayName = CupsShim().cupsGetOption(
136 "printer-info", printers[i].num_options, printers[i].options);
137 if (printerName == displayName) {
138 // The second arg to CupsShim().cupsCopyDest is called num_dests, but
139 // it actually copies num_dests + 1 elements.
140 CupsShim().cupsCopyDest(printers + i, 0, &printer);
141 break;
144 CupsShim().cupsFreeDests(numPrinters, printers);
146 #else
147 // On GTK, we only ever show the CUPS name of printers, so we can use
148 // cupsGetNamedDest directly.
150 const auto printerName = NS_ConvertUTF16toUTF8(aPrinterName);
151 printer = CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT, printerName.get(),
152 nullptr);
154 #endif
156 if (printer) {
157 // Since the printer name had to be passed by-value, we can move the
158 // name from that.
159 rv.emplace(PrinterInfo{std::move(aPrinterName), printer});
161 return rv;
164 mozilla::Maybe<PrinterInfo> nsPrinterListCUPS::PrinterBySystemName(
165 nsString aPrinterName) const {
166 mozilla::Maybe<PrinterInfo> rv;
167 if (!CupsShim().InitOkay()) {
168 return rv;
171 const auto printerName = NS_ConvertUTF16toUTF8(aPrinterName);
172 if (cups_dest_t* const printer = CupsShim().cupsGetNamedDest(
173 CUPS_HTTP_DEFAULT, printerName.get(), nullptr)) {
174 rv.emplace(PrinterInfo{std::move(aPrinterName), printer});
176 return rv;
179 nsresult nsPrinterListCUPS::SystemDefaultPrinterName(nsAString& aName) const {
180 aName.Truncate();
182 if (!CupsShim().InitOkay()) {
183 return NS_OK;
186 // Passing in nullptr for the name will return the default, if any.
187 cups_dest_t* dest =
188 CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT, /* name */ nullptr,
189 /* instance */ nullptr);
190 if (!dest) {
191 return NS_OK;
194 GetDisplayNameForPrinter(*dest, aName);
195 if (aName.IsEmpty()) {
196 CopyUTF8toUTF16(mozilla::MakeStringSpan(dest->name), aName);
199 CupsShim().cupsFreeDests(1, dest);
200 return NS_OK;