/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 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 nsPrinterCUPS_h___
#define nsPrinterCUPS_h___
#include "nsPrinterBase.h"
#include "nsPrintSettingsImpl.h"
#include "nsCUPSShim.h"
#include "nsString.h"
#include "mozilla/DataMutex.h"
#include "mozilla/FunctionRef.h"
#include "mozilla/RecursiveMutex.h"
/**
* @brief Interface to help implementing nsIPrinter using a CUPS printer.
*/
class nsPrinterCUPS final :
public nsPrinterBase {
public:
NS_IMETHOD GetName(nsAString& aName) override;
NS_IMETHOD GetSystemName(nsAString& aName) override;
bool SupportsDuplex()
const final;
bool SupportsColor()
const final;
bool SupportsMonochrome()
const final;
bool SupportsCollation()
const final;
PrinterInfo CreatePrinterInfo()
const final;
MarginDouble GetMarginsForPaper(nsString aPaperId)
const final {
MOZ_ASSERT_UNREACHABLE(
"The CUPS API requires us to always get the margin when fetching the "
"paper list so there should be no need to query it separately");
return {};
}
nsPrinterCUPS() =
delete;
nsPrinterCUPS(
const mozilla::CommonPaperInfoArray* aArray,
const nsCUPSShim& aShim, nsString aDisplayName,
cups_dest_t* aPrinter)
: nsPrinterBase(aArray),
mShim(aShim),
mDisplayName(std::move(aDisplayName)),
mPrinterInfoMutex(CUPSPrinterInfo{aPrinter},
"nsPrinterCUPS::mPrinterInfoMutex") {}
static void ForEachExtraMonochromeSetting(
mozilla::FunctionRef<
void(
const nsACString&,
const nsACString&)>);
private:
struct CUPSPrinterInfo {
explicit constexpr CUPSPrinterInfo(cups_dest_t* aPrinter)
: mPrinter(aPrinter) {}
cups_dest_t* mPrinter;
cups_dinfo_t* mPrinterInfo = nullptr;
uint64_t mCUPSMajor = 0;
uint64_t mCUPSMinor = 0;
uint64_t mCUPSPatch = 0;
// Whether we have attempted to fetch mPrinterInfo with CUPS_HTTP_DEFAULT.
bool mTriedInitWithDefault =
false;
// Whether we have attempted to fetch mPrinterInfo with a connection.
bool mTriedInitWithConnection =
false;
CUPSPrinterInfo() =
delete;
CUPSPrinterInfo(
const CUPSPrinterInfo&) =
delete;
CUPSPrinterInfo(CUPSPrinterInfo&& aOther)
: mPrinter(aOther.mPrinter),
mPrinterInfo(aOther.mPrinterInfo),
mCUPSMajor(aOther.mCUPSMajor),
mCUPSMinor(aOther.mCUPSMinor),
mCUPSPatch(aOther.mCUPSPatch) {
aOther.mPrinter = nullptr;
aOther.mPrinterInfo = nullptr;
}
};
using PrinterInfoMutex =
mozilla::DataMutexBase<CUPSPrinterInfo, mozilla::RecursiveMutex>;
using PrinterInfoLock = PrinterInfoMutex::AutoLock;
~nsPrinterCUPS();
/**
* Retrieves the localized name for a given media (paper).
* Returns nullptr if the name cannot be localized.
*/
const char* LocalizeMediaName(http_t& aConnection, cups_size_t& aMedia)
const;
void GetPrinterName(nsAString& aName)
const;
// Little util for getting support flags using the direct CUPS names.
bool Supports(
const char* aOption,
const char* aValue)
const;
// Returns support value if CUPS meets the minimum version, otherwise returns
// |aDefault|
bool IsCUPSVersionAtLeast(uint64_t aCUPSMajor, uint64_t aCUPSMinor,
uint64_t aCUPSPatch)
const;
const char* FindCUPSOption(PrinterInfoLock& aLock,
const char* name)
const {
const cups_dest_t*
const printer = aLock->mPrinter;
return mShim.cupsGetOption(name, printer->num_options, printer->options);
}
class Connection {
public:
http_t* GetConnection(cups_dest_t* aDest);
inline explicit Connection(
const nsCUPSShim& aShim) : mShim(aShim) {}
Connection() =
delete;
~Connection();
protected:
const nsCUPSShim& mShim;
http_t* mConnection = CUPS_HTTP_DEFAULT;
bool mWasInited =
false;
};
PrintSettingsInitializer DefaultSettings(Connection& aConnection)
const;
nsTArray<mozilla::PaperInfo> PaperList(Connection& aConnection)
const;
/**
* Attempts to populate the CUPSPrinterInfo object.
* This usually works with the CUPS default connection,
* but has been known to require an established connection
* on older versions of Ubuntu (18 and below).
*/
PrinterInfoLock TryEnsurePrinterInfo(
http_t*
const aConnection = CUPS_HTTP_DEFAULT)
const {
PrinterInfoLock lock = mPrinterInfoMutex.Lock();
TryEnsurePrinterInfo(lock, aConnection);
return lock;
}
/**
* TryEnsurePrinterInfo that uses a caller-provided PrinterInfoLock.
*
* This can be used to avoid unnecessarily redundant locking of
* mPrinterInfoLock when getting a connection through
* Connection::GetConnection and then passing that into TryEnsurePrinterInfo.
*/
void TryEnsurePrinterInfo(PrinterInfoLock& aLock,
http_t*
const aConnection)
const;
const nsCUPSShim& mShim;
nsString mDisplayName;
mutable PrinterInfoMutex mPrinterInfoMutex;
};
// There's no standard setting in Core Printing for monochrome. Or rather,
// there is (PMSetColorMode) but it does nothing. Similarly, the relevant gtk
// setting only works on Windows, yay.
//
// So on CUPS the right setting to use depends on the print driver. So we set /
// look for a variety of driver-specific keys that are known to work across
// printers.
//
// We set all the known settings, because the alternative to that is parsing ppd
// files from the printer and find the relevant known choices that can apply,
// and that is a lot more complex, similarly sketchy (requires the same amount
// of driver-specific knowledge), and requires using deprecated CUPS APIs.
#define CUPS_EACH_MONOCHROME_PRINTER_SETTING(macro_) \
macro_(
"ColorModel",
"Gray")
/* Generic */ \
macro_(
"BRMonoColor",
"Mono")
/* Brother */ \
macro_(
"BRPrintQuality",
"Black")
/* Brother */ \
macro_(
"CNIJGrayScale",
"1")
/* Canon */ \
macro_(
"CNGrayscale",
"True")
/* Canon */ \
macro_(
"INK",
"MONO")
/* Epson */ \
macro_(
"HPColorMode",
"GrayscalePrint")
/* HP */ \
macro_(
"ColorMode",
"Mono")
/* Samsung */ \
macro_(
"PrintoutMode",
"Normal.Gray")
/* Foomatic */ \
macro_(
"ProcessColorModel",
"Mono")
/* Samsung */ \
macro_(
"ARCMode",
"CMBW")
/* Sharp */ \
macro_(
"XRXColor",
"BW")
/* Xerox */ \
macro_(
"XROutputColor",
"PrintAsGrayscale")
/* Xerox, bug 1676191#c32 */ \
macro_(
"SelectColor",
"Grayscale")
/* Konica Minolta */ \
macro_(
"OKControl",
"Gray")
/* Oki */ \
macro_(
"BLW",
"TrueM")
/* Lexmark */ \
macro_(
"EPRendering",
"None")
/* Epson */
#endif /* nsPrinterCUPS_h___ */