diff --git a/win-linux/src/cascapplicationmanagerwrapper_private.h b/win-linux/src/cascapplicationmanagerwrapper_private.h index 74e1f909f..80619aab8 100644 --- a/win-linux/src/cascapplicationmanagerwrapper_private.h +++ b/win-linux/src/cascapplicationmanagerwrapper_private.h @@ -77,7 +77,9 @@ public: virtual ~CAscApplicationManagerWrapper_Private() {} - virtual void initializeApp() {} + virtual void initializeApp() { + m_printData->setAppDataPath(m_appmanager.m_oSettings.app_data_path); + } virtual bool processEvent(NSEditorApi::CAscCefMenuEvent * event) { if ( detectDocumentOpening(*event) ) return true; diff --git a/win-linux/src/cprintdata.cpp b/win-linux/src/cprintdata.cpp index 6267a2532..f9ba1839e 100644 --- a/win-linux/src/cprintdata.cpp +++ b/win-linux/src/cprintdata.cpp @@ -45,6 +45,48 @@ # include #endif +#ifdef _WIN32 +static QString getDriverName(LPWSTR printerName) +{ + QString name; + HANDLE hPrinter = nullptr; + if (!OpenPrinter(printerName, &hPrinter, nullptr)) { + return name; + } + DWORD needed = 0; + GetPrinterDriver(hPrinter, nullptr, 1, nullptr, 0, &needed); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + ClosePrinter(hPrinter); + return name; + } + std::vector buf(needed); + if (!GetPrinterDriver(hPrinter, nullptr, 1, buf.data(), needed, &needed)) { + ClosePrinter(hPrinter); + return name; + } + DRIVER_INFO_1 *info = reinterpret_cast(buf.data()); + if (info->pName) + name = QString::fromWCharArray(info->pName); + ClosePrinter(hPrinter); + return name; +} +#endif + +static bool jsonArrayContainsDriverName(const QJsonArray &array, const QString &name, QJsonObject &printerObject) +{ + if (name.isEmpty()) + return false; + for (const QJsonValue &value : array) { + if (value.isObject()) { + QJsonObject obj = value.toObject(); + if (obj.contains("driver") && obj.value("driver").toString() == name) { + printerObject = obj; + return true; + } + } + } + return false; +} static QString getFirstPrinterName(const QJsonObject &json) { @@ -75,6 +117,7 @@ public: int paper_width = 0, paper_height = 0; QString size_preset; + std::wstring app_data_path; QJsonObject printers_capabilities_json; int sender_id = -1; int copies_count = 1; @@ -179,7 +222,17 @@ public: auto getPrintersCapabilitiesJson() const -> QJsonObject { - QJsonArray printersArray; + bool needUpdateCache = false; + QJsonArray printersArray, cachedPrintersArray; + std::wstring user_data_path = app_data_path; + const QString printers_cache = QString::fromStdWString(user_data_path.append(L"/printers.cache")); + if (QFile::exists(printers_cache)) { + QJsonObject cache = Utils::parseJsonFile(printers_cache); + if (!cache.isEmpty() && cache.contains("printers")) { + cachedPrintersArray = cache["printers"].toArray(); + } + } + #ifdef _WIN32 DWORD need = 0, ret = 0; EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, nullptr, 0, &need, &ret); @@ -187,10 +240,21 @@ public: if (EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, buf.data(), need, &need, &ret)) { PRINTER_INFO_4 *printers = reinterpret_cast(buf.data()); for (DWORD i = 0; i < ret; ++i) { + QJsonObject printerObject; + const QString driverName = getDriverName(printers[i].pPrinterName); + if (jsonArrayContainsDriverName(cachedPrintersArray, driverName, printerObject)) { + printerObject["name"] = QString::fromWCharArray(printers[i].pPrinterName); + printersArray.append(printerObject); + continue; + } else { + if (!needUpdateCache) + needUpdateCache = true; + } + bool duplex_supported = (DeviceCapabilities(printers[i].pPrinterName, NULL, DC_DUPLEX, NULL, NULL) == 1); bool color_supported = (DeviceCapabilities(printers[i].pPrinterName, NULL, DC_COLORDEVICE, NULL, NULL) == 1); - QJsonObject printerObject; + printerObject["driver"] = driverName; printerObject["name"] = QString::fromWCharArray(printers[i].pPrinterName); printerObject["duplex_supported"] = duplex_supported; printerObject["color_supported"] = color_supported; @@ -240,9 +304,26 @@ public: if (!ppd) continue; ppd_file_t *ppdF = ppdOpenFile(ppd); + if (!ppdF) { + unlink(ppd); + continue; + } + QJsonObject printerObject; + const QString driverName = ppdF->nickname ? QString::fromUtf8(ppdF->nickname) : ""; + if (jsonArrayContainsDriverName(cachedPrintersArray, driverName, printerObject)) { + printerObject["name"] = QString::fromUtf8(dest->name); + printersArray.append(printerObject); + ppdClose(ppdF); + unlink(ppd); + continue; + } else { + if (!needUpdateCache) + needUpdateCache = true; + } + bool duplex_supported = ppdFindOption(ppdF, "Duplex"); - QJsonObject printerObject; + printerObject["driver"] = driverName; printerObject["name"] = QString::fromUtf8(dest->name); printerObject["duplex_supported"] = duplex_supported; printerObject["color_supported"] = false; @@ -276,12 +357,17 @@ public: } printersArray.append(printerObject); ppdClose(ppdF); + unlink(ppd); } cupsFreeDests(num_dests, dests); } #endif QJsonObject rootObject; rootObject["printers"] = printersArray; + if (needUpdateCache) { + const QByteArray json = QJsonDocument(rootObject).toJson(QJsonDocument::Compact); + Utils::writeFile(printers_cache, json); + } return rootObject; } @@ -334,6 +420,11 @@ auto CPrintData::printerInfo() const -> QPrinterInfo return m_priv->printer_info; } +void CPrintData::setAppDataPath(const std::wstring &app_data_path) +{ + m_priv->app_data_path = app_data_path; +} + auto CPrintData::setPrinterInfo(const QPrinterInfo& info) -> void { GET_REGISTRY_USER(reg_user); diff --git a/win-linux/src/cprintdata.h b/win-linux/src/cprintdata.h index b0257f9c6..fc83f2731 100644 --- a/win-linux/src/cprintdata.h +++ b/win-linux/src/cprintdata.h @@ -50,6 +50,7 @@ public: auto init(NSEditorApi::CAscPrintEnd *) -> void; auto init(int, NSEditorApi::CAscPrintEnd *) -> void; auto printerInfo() const -> QPrinterInfo; + auto setAppDataPath(const std::wstring&) -> void; auto setPrinterInfo(const QPrinterInfo&) -> void; auto setPrinterInfo(const QPrinter&) -> void; auto pageSize() const -> QPageSize;