diff --git a/win-linux/defaults.pri b/win-linux/defaults.pri index 935257971..5fc6df513 100644 --- a/win-linux/defaults.pri +++ b/win-linux/defaults.pri @@ -233,7 +233,7 @@ core_linux { CONFIG += link_pkgconfig PKGCONFIG += glib-2.0 gtk+-3.0 atk gtk+-unix-print-3.0 xcb - LIBS += -lX11 -lX11-xcb + LIBS += -lX11 -lX11-xcb -lcups cef_version_107 { LIBS += $$PWD/../../build_tools/tools/linux/sysroot/ubuntu14/libdbus-1.so.3 diff --git a/win-linux/src/cascapplicationmanagerwrapper.cpp b/win-linux/src/cascapplicationmanagerwrapper.cpp index fb7a8789e..092b5dbb1 100644 --- a/win-linux/src/cascapplicationmanagerwrapper.cpp +++ b/win-linux/src/cascapplicationmanagerwrapper.cpp @@ -1095,6 +1095,22 @@ void CAscApplicationManagerWrapper::onDocumentReady(int uid) #ifdef _WIN32 Association::instance().chekForAssociations(uid); #endif + + if (uid > -1 && printData().printerCapabilitiesReady()) + AscAppManager::sendCommandTo(GetViewById(uid), L"printer:config", printData().getPrinterCapabilitiesJson().toStdWString()); + + static bool check_printers = false; + if (!check_printers) { + check_printers = true; + + printData().queryPrinterCapabilitiesAsync([=](const QString &json) { + // qDebug().noquote() << json; + for (int _uid : GetViewsId()) { + if (_uid > -1) + AscAppManager::sendCommandTo(GetViewById(_uid), L"printer:config", json.toStdWString()); + } + }); + } } void CAscApplicationManagerWrapper::startApp() diff --git a/win-linux/src/cprintdata.cpp b/win-linux/src/cprintdata.cpp index 0e557ea83..b736d22c2 100644 --- a/win-linux/src/cprintdata.cpp +++ b/win-linux/src/cprintdata.cpp @@ -33,13 +33,21 @@ #include "cprintdata.h" #include "utils.h" #include "defines.h" +#include +#include #include #include #include +#include #include +#ifdef __linux__ +# include +# include +#endif -class CPrintData::CPrintDataPrivate +class CPrintData::CPrintDataPrivate : public QObject { + Q_OBJECT public: QPrinterInfo printer_info; QPrintDialog::PrintRange print_range{QPrintDialog::PrintRange::AllPages}; @@ -53,8 +61,11 @@ public: int paper_width = 0, paper_height = 0; QString size_preset; + QString printers_capabilities_json; int sender_id = -1; int copies_count = 1; + FnVoidStr m_query_callback = nullptr; + std::future m_future; auto parseJsonOptions(const std::wstring& json) -> bool { QJsonObject jsonOptions = Utils::parseJsonString(json); @@ -142,6 +153,109 @@ public: parseJsonOptions(data->get_Options()); } + auto getPrintersCapabilitiesJson() const -> QString + { + QJsonArray printersArray; +#ifdef _WIN32 + DWORD need = 0, ret = 0; + EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 2, nullptr, 0, &need, &ret); + std::vector buf(need); + if (EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 2, buf.data(), need, &need, &ret)) { + PRINTER_INFO_2 *printers = reinterpret_cast(buf.data()); + for (DWORD i = 0; i < ret; ++i) { + LPDEVMODE pDevMode = printers[i].pDevMode; + bool duplex_supported = (pDevMode && (pDevMode->dmFields & DM_DUPLEX)); + + QJsonObject printerObject; + printerObject["name"] = QString::fromWCharArray(printers[i].pPrinterName); + printerObject["duplex_supported"] = duplex_supported; + + constexpr int PAPER_NAME_LENGTH = 64; + bool paperNamesSuccess = false, paperSizeSuccess = false; + std::vector paperNames; + std::vector paperSize; + int paperNamesCount = DeviceCapabilities(printers[i].pPrinterName, printers[i].pPortName, DC_PAPERNAMES, NULL, NULL); + if (paperNamesCount > 0) { + paperNames.assign(paperNamesCount * PAPER_NAME_LENGTH, L'\0'); + int res = DeviceCapabilities(printers[i].pPrinterName, printers[i].pPortName, DC_PAPERNAMES, paperNames.data(), NULL); + if (res == paperNamesCount) + paperNamesSuccess = true; + } + int paperSizeCount = DeviceCapabilities(printers[i].pPrinterName, printers[i].pPortName, DC_PAPERSIZE, NULL, NULL); + if (paperSizeCount > 0) { + paperSize.assign(paperSizeCount, {0, 0}); + int res = DeviceCapabilities(printers[i].pPrinterName, printers[i].pPortName, DC_PAPERSIZE, (LPWSTR)paperSize.data(), NULL); + if (res == paperSizeCount) + paperSizeSuccess = true; + } + if (paperNamesSuccess && paperSizeSuccess && paperNamesCount == paperSizeCount) { + QJsonArray paperArray; + for (int j = 0; j < paperNamesCount; ++j) { + if (paperSize[j].x > 0 && paperSize[j].y > 0) { + std::wstring paperName(&paperNames[j * PAPER_NAME_LENGTH], PAPER_NAME_LENGTH); + QJsonObject paperObj; + paperObj["name"] = QString::fromWCharArray(paperName.c_str()); + paperObj["width"] = (double)paperSize[j].x/10; + paperObj["height"] = (double)paperSize[j].y/10; + paperArray.append(paperObj); + } + } + printerObject["paper_supported"] = paperArray; + } + printersArray.append(printerObject); + } + } +#else + cups_dest_t *dests = nullptr; + int num_dests = cupsGetDests(&dests); + if (dests) { + for (int i = 0; i < num_dests; i++) { + cups_dest_t *dest = &dests[i]; + const char *ppd = cupsGetPPD(dest->name); + ppd_file_t *ppdF = ppdOpenFile(ppd); + bool duplex_supported = ppdFindOption(ppdF, "Duplex"); + + QJsonObject printerObject; + printerObject["name"] = QString::fromUtf8(dest->name); + printerObject["duplex_supported"] = duplex_supported; + + ppd_option_t *option = ppdFirstOption(ppdF); + while (option) { + if (strcmp(option->keyword, "PageSize") == 0) { + QJsonArray paperArray; + for (int j = 0; j < option->num_choices; j++) { + if (strcmp(option->choices[j].choice, "Custom") != 0) { + if (ppd_size_t *size = ppdPageSize(ppdF, option->choices[j].choice)) { + QJsonObject paperObj; + paperObj["name"] = QString::fromUtf8(option->choices[j].choice); + paperObj["width"] = qRound(25.4 * size->width / 72.0); + paperObj["height"] = qRound(25.4 * size->length / 72.0); + paperArray.append(paperObj); + } + } + } + printerObject["paper_supported"] = paperArray; + } + option = ppdNextOption(ppdF); + } + printersArray.append(printerObject); + ppdClose(ppdF); + } + cupsFreeDests(num_dests, dests); + } +#endif + QJsonObject rootObject; + rootObject["printers"] = printersArray; + return QJsonDocument(rootObject).toJson(QJsonDocument::Indented); + } + +public slots: + void onPrinterCapabilitiesReady(QString json) + { + printers_capabilities_json = json; + if (m_query_callback) + m_query_callback(json); + } }; CPrintData::CPrintData() @@ -152,6 +266,8 @@ CPrintData::CPrintData() CPrintData::~CPrintData() { + if (m_priv->m_future.valid()) + m_priv->m_future.wait(); delete m_priv, m_priv = nullptr; } @@ -287,3 +403,24 @@ auto CPrintData::duplexMode() const -> QPrinter::DuplexMode { return m_priv->duplex_mode; } + +bool CPrintData::printerCapabilitiesReady() const +{ + return !m_priv->printers_capabilities_json.isEmpty(); +} + +QString CPrintData::getPrinterCapabilitiesJson() const +{ + return m_priv->printers_capabilities_json; +} + +auto CPrintData::queryPrinterCapabilitiesAsync(const FnVoidStr &callback) const -> void +{ + m_priv->m_query_callback = callback; + m_priv->m_future = std::async(std::launch::async, [=]() { + QString json = m_priv->getPrintersCapabilitiesJson(); + QMetaObject::invokeMethod(m_priv, "onPrinterCapabilitiesReady", Qt::QueuedConnection, Q_ARG(QString, json)); + }); +} + +#include "cprintdata.moc" diff --git a/win-linux/src/cprintdata.h b/win-linux/src/cprintdata.h index c48660d23..f097b83e5 100644 --- a/win-linux/src/cprintdata.h +++ b/win-linux/src/cprintdata.h @@ -36,6 +36,10 @@ #include "applicationmanager_events.h" #include #include +#include + +typedef std::function FnVoidStr; + class CPrintData { @@ -59,6 +63,9 @@ public: auto viewId() const -> int; auto copiesCount() const -> int; auto duplexMode() const -> QPrinter::DuplexMode; + auto printerCapabilitiesReady() const -> bool; + auto getPrinterCapabilitiesJson() const -> QString; + auto queryPrinterCapabilitiesAsync(const FnVoidStr &callback) const -> void; private: class CPrintDataPrivate; diff --git a/win-linux/src/platform_linux/gtkprintdialog.cpp b/win-linux/src/platform_linux/gtkprintdialog.cpp index 62fa47d0d..20508067c 100644 --- a/win-linux/src/platform_linux/gtkprintdialog.cpp +++ b/win-linux/src/platform_linux/gtkprintdialog.cpp @@ -122,44 +122,22 @@ static GtkPageRange *get_page_ranges(GtkEntry *entry, gint *num_ranges) return NULL; } -auto gtkPaperNameFromPageSize(PageSize page_size)->QString +auto gtkPaperNameFromPageSize(const QSizeF &size)->QString { - switch (page_size) { - case PageSize::A0: - return "iso_a0"; - case PageSize::A1: - return "iso_a1"; - case PageSize::A2: - return "iso_a2"; - case PageSize::A3: - return "iso_a3"; - case PageSize::A4: - return "iso_a4"; - case PageSize::A5: - return "iso_a5"; - case PageSize::A6: - return "iso_a6"; - case PageSize::B5: - return "ppd_EnvB5"; // "iso_b5" - not working - case PageSize::Tabloid: - return "na_ledger"; - case PageSize::EnvelopeDL: - return "iso_dl"; - case PageSize::Comm10E: - return "na_number-10"; - case PageSize::SuperB: - return "na_super-b"; -// case PageSize::TabloidExtra: -// return "na_ledger"; - case PageSize::Letter: - return "na_letter"; - case PageSize::Legal: - return "na_legal"; - case PageSize::EnvelopeChou3: - return "jpn_chou3"; - default: - return QPageSize::name((QPageSize::PageSizeId)page_size); + QString gtkPaperName; + constexpr double diff = 1.0; + GList *paper_sizes = gtk_paper_size_get_paper_sizes(FALSE); + for (GList *it = paper_sizes; it != nullptr; it = it->next) { + GtkPaperSize *psize = (GtkPaperSize*)it->data; + double width = gtk_paper_size_get_width(psize, GTK_UNIT_MM); + double height = gtk_paper_size_get_height(psize, GTK_UNIT_MM); + if (std::abs(size.width() - width) < diff && std::abs(size.height() - height) < diff) { + gtkPaperName = gtk_paper_size_get_name(psize); + break; + } } + g_list_free_full(paper_sizes, (GDestroyNotify)gtk_paper_size_free); + return gtkPaperName; } GtkPrintDialog::GtkPrintDialog(QPrinter *printer, QWidget *parent) : @@ -342,8 +320,8 @@ QDialog::DialogCode GtkPrintDialog::exec() gtk_page_setup_set_bottom_margin(page_setup, bottom_in, unit); QPageSize ps = m_printer->pageLayout().pageSize(); - QSize page_size = ps.size(QPageSize::Millimeter).toSize(); - const QString paper_name = gtkPaperNameFromPageSize(m_printer->pageSize()); + QSizeF page_size = ps.size(QPageSize::Millimeter); + const QString paper_name = gtkPaperNameFromPageSize(page_size); GtkPaperSize *psize = gtk_paper_size_new_custom( paper_name.toUtf8().data(), ps.name().toUtf8().data(), diff --git a/win-linux/src/platform_win/printdialog.cpp b/win-linux/src/platform_win/printdialog.cpp index 344250860..7ff845f47 100644 --- a/win-linux/src/platform_win/printdialog.cpp +++ b/win-linux/src/platform_win/printdialog.cpp @@ -45,9 +45,9 @@ typedef QPageSize::PageSizeId PageSize; -auto getPaperSizeFromPageSize(PageSize page_size)->int +auto getPaperSizeFromPageSize(LPWSTR pPrinterName, const QPageSize &ps)->int { - switch (page_size) { + switch (ps.id()) { // case PageSize::A0: // return DMPAPER_USER; // case PageSize::A1: @@ -80,9 +80,37 @@ auto getPaperSizeFromPageSize(PageSize page_size)->int return DMPAPER_LEGAL; case PageSize::EnvelopeChou3: return DMPAPER_JENV_CHOU3; - default: + default: { + bool paperNamesSuccess = false, paperSizeSuccess = false; + std::vector papers; + std::vector paperSize; + int papersCount = DeviceCapabilities(pPrinterName, NULL, DC_PAPERS, NULL, NULL); + if (papersCount > 0) { + papers.assign(papersCount, 0); + int res = DeviceCapabilities(pPrinterName, NULL, DC_PAPERS, (LPWSTR)papers.data(), NULL); + if (res == papersCount) + paperNamesSuccess = true; + } + int paperSizeCount = DeviceCapabilities(pPrinterName, NULL, DC_PAPERSIZE, NULL, NULL); + if (paperSizeCount > 0) { + paperSize.assign(paperSizeCount, {0, 0}); + int res = DeviceCapabilities(pPrinterName, NULL, DC_PAPERSIZE, (LPWSTR)paperSize.data(), NULL); + if (res == paperSizeCount) + paperSizeSuccess = true; + } + if (paperNamesSuccess && paperSizeSuccess && papersCount == paperSizeCount) { + constexpr double diff = 1.0; + QSizeF size = ps.size(QPageSize::Millimeter); + for (int j = 0; j < papersCount; ++j) { + double width = (double)paperSize[j].x/10; + double height = (double)paperSize[j].y/10; + if (std::abs(size.width() - width) < diff && std::abs(size.height() - height) < diff) + return papers[j]; + } + } return DMPAPER_USER; } + } } #ifndef __OS_WIN_XP @@ -337,15 +365,18 @@ QDialog::DialogCode PrintDialog::exec() (qt_duplex == QPrinter::DuplexShortSide) ? DMDUP_HORIZONTAL : DMDUP_SIMPLEX; } + int paper_size = getPaperSizeFromPageSize(pPrinterName, m_printer->pageLayout().pageSize()); if (pDevMode->dmFields & DM_PAPERSIZE) - pDevMode->dmPaperSize = getPaperSizeFromPageSize(m_printer->pageLayout().pageSize().id()); + pDevMode->dmPaperSize = paper_size; - QPageSize ps = m_printer->pageLayout().pageSize(); - QSizeF page_size = ps.size(QPageSize::Millimeter); - if (pDevMode->dmFields & DM_PAPERWIDTH) - pDevMode->dmPaperWidth = qRound(10 * page_size.width()); - if (pDevMode->dmFields & DM_PAPERLENGTH) - pDevMode->dmPaperLength = qRound(10 * page_size.height()); + if (paper_size == DMPAPER_USER || !(pDevMode->dmFields & DM_PAPERSIZE)) { + QPageSize ps = m_printer->pageLayout().pageSize(); + QSizeF page_size = ps.size(QPageSize::Millimeter); + if (pDevMode->dmFields & DM_PAPERWIDTH) + pDevMode->dmPaperWidth = qRound(10 * page_size.width()); + if (pDevMode->dmFields & DM_PAPERLENGTH) + pDevMode->dmPaperLength = qRound(10 * page_size.height()); + } dwRet = DocumentProperties(parent_hwnd, hPrinter, pPrinterName, pDevMode, pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); }