summaryrefslogtreecommitdiffstats
path: root/src/printsupport/kernel/qcups.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/printsupport/kernel/qcups.cpp')
-rw-r--r--src/printsupport/kernel/qcups.cpp446
1 files changed, 446 insertions, 0 deletions
diff --git a/src/printsupport/kernel/qcups.cpp b/src/printsupport/kernel/qcups.cpp
new file mode 100644
index 0000000000..76050d9d71
--- /dev/null
+++ b/src/printsupport/kernel/qcups.cpp
@@ -0,0 +1,446 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qdebug.h>
+#include "qcups_p.h"
+#include "qprinterinfo_unix_p.h"
+
+#ifndef QT_NO_CUPS
+
+#ifndef QT_LINUXBASE // LSB merges everything into cups.h
+# include <cups/language.h>
+#endif
+#include <qtextcodec.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef int (*CupsGetDests)(cups_dest_t **dests);
+typedef void (*CupsFreeDests)(int num_dests, cups_dest_t *dests);
+typedef const char* (*CupsGetPPD)(const char *printer);
+typedef int (*CupsMarkOptions)(ppd_file_t *ppd, int num_options, cups_option_t *options);
+typedef ppd_file_t* (*PPDOpenFile)(const char *filename);
+typedef void (*PPDMarkDefaults)(ppd_file_t *ppd);
+typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
+typedef void (*PPDClose)(ppd_file_t *ppd);
+typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
+typedef void (*CupsFreeOptions)(int num_options, cups_option_t *options);
+typedef void (*CupsSetDests)(int num_dests, cups_dest_t *dests);
+typedef cups_lang_t* (*CupsLangGet)(const char *language);
+typedef const char* (*CupsLangEncoding)(cups_lang_t *language);
+typedef int (*CupsAddOption)(const char *name, const char *value, int num_options, cups_option_t **options);
+typedef int (*CupsTempFd)(char *name, int len);
+typedef int (*CupsPrintFile)(const char * name, const char * filename, const char * title, int num_options, cups_option_t * options);
+
+static bool cupsLoaded = false;
+static int qt_cups_num_printers = 0;
+static CupsGetDests _cupsGetDests = 0;
+static CupsFreeDests _cupsFreeDests = 0;
+static CupsGetPPD _cupsGetPPD = 0;
+static PPDOpenFile _ppdOpenFile = 0;
+static PPDMarkDefaults _ppdMarkDefaults = 0;
+static PPDClose _ppdClose = 0;
+static CupsMarkOptions _cupsMarkOptions = 0;
+static PPDMarkOption _ppdMarkOption = 0;
+static CupsFreeOptions _cupsFreeOptions = 0;
+static CupsSetDests _cupsSetDests = 0;
+static CupsLangGet _cupsLangGet = 0;
+static CupsLangEncoding _cupsLangEncoding = 0;
+static CupsAddOption _cupsAddOption = 0;
+static CupsTempFd _cupsTempFd = 0;
+static CupsPrintFile _cupsPrintFile = 0;
+
+static void resolveCups()
+{
+ QLibrary cupsLib(QLatin1String("cups"), 2);
+ if(cupsLib.load()) {
+ _cupsGetDests = (CupsGetDests) cupsLib.resolve("cupsGetDests");
+ _cupsFreeDests = (CupsFreeDests) cupsLib.resolve("cupsFreeDests");
+ _cupsGetPPD = (CupsGetPPD) cupsLib.resolve("cupsGetPPD");
+ _cupsLangGet = (CupsLangGet) cupsLib.resolve("cupsLangGet");
+ _cupsLangEncoding = (CupsLangEncoding) cupsLib.resolve("cupsLangEncoding");
+ _ppdOpenFile = (PPDOpenFile) cupsLib.resolve("ppdOpenFile");
+ _ppdMarkDefaults = (PPDMarkDefaults) cupsLib.resolve("ppdMarkDefaults");
+ _ppdClose = (PPDClose) cupsLib.resolve("ppdClose");
+ _cupsMarkOptions = (CupsMarkOptions) cupsLib.resolve("cupsMarkOptions");
+ _ppdMarkOption = (PPDMarkOption) cupsLib.resolve("ppdMarkOption");
+ _cupsFreeOptions = (CupsFreeOptions) cupsLib.resolve("cupsFreeOptions");
+ _cupsSetDests = (CupsSetDests) cupsLib.resolve("cupsSetDests");
+ _cupsAddOption = (CupsAddOption) cupsLib.resolve("cupsAddOption");
+ _cupsTempFd = (CupsTempFd) cupsLib.resolve("cupsTempFd");
+ _cupsPrintFile = (CupsPrintFile) cupsLib.resolve("cupsPrintFile");
+
+ if (_cupsGetDests && _cupsFreeDests) {
+ cups_dest_t *printers;
+ int num_printers = _cupsGetDests(&printers);
+ if (num_printers)
+ _cupsFreeDests(num_printers, printers);
+ qt_cups_num_printers = num_printers;
+ }
+ }
+ cupsLoaded = true;
+}
+
+// ================ CUPS Support class ========================
+
+QCUPSSupport::QCUPSSupport()
+ :
+ prnCount(0),
+ printers(0),
+ page_sizes(0),
+ currPrinterIndex(0),
+ currPPD(0)
+{
+ if (!cupsLoaded)
+ resolveCups();
+
+ // getting all available printers
+ if (!isAvailable())
+ return;
+
+ prnCount = _cupsGetDests(&printers);
+
+ for (int i = 0; i < prnCount; ++i) {
+ if (printers[i].is_default) {
+ currPrinterIndex = i;
+ setCurrentPrinter(i);
+ break;
+ }
+ }
+
+#ifndef QT_NO_TEXTCODEC
+ cups_lang_t *cupsLang = _cupsLangGet(0);
+ codec = QTextCodec::codecForName(_cupsLangEncoding(cupsLang));
+ if (!codec)
+ codec = QTextCodec::codecForLocale();
+#endif
+}
+
+QCUPSSupport::~QCUPSSupport()
+{
+ if (currPPD)
+ _ppdClose(currPPD);
+ if (prnCount)
+ _cupsFreeDests(prnCount, printers);
+}
+
+int QCUPSSupport::availablePrintersCount() const
+{
+ return prnCount;
+}
+
+const cups_dest_t* QCUPSSupport::availablePrinters() const
+{
+ return printers;
+}
+
+const ppd_file_t* QCUPSSupport::currentPPD() const
+{
+ return currPPD;
+}
+
+const ppd_file_t* QCUPSSupport::setCurrentPrinter(int index)
+{
+ Q_ASSERT(index >= 0 && index <= prnCount);
+ if (index == prnCount)
+ return 0;
+
+ currPrinterIndex = index;
+
+ if (currPPD)
+ _ppdClose(currPPD);
+ currPPD = 0;
+ page_sizes = 0;
+
+ const char *ppdFile = _cupsGetPPD(printers[index].name);
+
+ if (!ppdFile)
+ return 0;
+
+ currPPD = _ppdOpenFile(ppdFile);
+ unlink(ppdFile);
+
+ // marking default options
+ _ppdMarkDefaults(currPPD);
+
+ // marking options explicitly set
+ _cupsMarkOptions(currPPD, printers[currPrinterIndex].num_options, printers[currPrinterIndex].options);
+
+ // getting pointer to page sizes
+ page_sizes = ppdOption("PageSize");
+
+ return currPPD;
+}
+
+int QCUPSSupport::currentPrinterIndex() const
+{
+ return currPrinterIndex;
+}
+
+bool QCUPSSupport::isAvailable()
+{
+ if(!cupsLoaded)
+ resolveCups();
+
+ return _cupsGetDests &&
+ _cupsFreeDests &&
+ _cupsGetPPD &&
+ _ppdOpenFile &&
+ _ppdMarkDefaults &&
+ _ppdClose &&
+ _cupsMarkOptions &&
+ _ppdMarkOption &&
+ _cupsFreeOptions &&
+ _cupsSetDests &&
+ _cupsLangGet &&
+ _cupsLangEncoding &&
+ _cupsAddOption &&
+ (qt_cups_num_printers > 0);
+}
+
+const ppd_option_t* QCUPSSupport::ppdOption(const char *key) const
+{
+ if (currPPD) {
+ for (int gr = 0; gr < currPPD->num_groups; ++gr) {
+ for (int opt = 0; opt < currPPD->groups[gr].num_options; ++opt) {
+ if (qstrcmp(currPPD->groups[gr].options[opt].keyword, key) == 0)
+ return &currPPD->groups[gr].options[opt];
+ }
+ }
+ }
+ return 0;
+}
+
+const cups_option_t* QCUPSSupport::printerOption(const QString &key) const
+{
+ for (int i = 0; i < printers[currPrinterIndex].num_options; ++i) {
+ if (QLatin1String(printers[currPrinterIndex].options[i].name) == key)
+ return &printers[currPrinterIndex].options[i];
+ }
+ return 0;
+}
+
+const ppd_option_t* QCUPSSupport::pageSizes() const
+{
+ return page_sizes;
+}
+
+int QCUPSSupport::markOption(const char* name, const char* value)
+{
+ return _ppdMarkOption(currPPD, name, value);
+}
+
+void QCUPSSupport::saveOptions(QList<const ppd_option_t*> options, QList<const char*> markedOptions)
+{
+ int oldOptionCount = printers[currPrinterIndex].num_options;
+ cups_option_t* oldOptions = printers[currPrinterIndex].options;
+
+ int newOptionCount = 0;
+ cups_option_t* newOptions = 0;
+
+ // copying old options that are not on the new list
+ for (int i = 0; i < oldOptionCount; ++i) {
+ bool contains = false;
+ for (int j = 0; j < options.count(); ++j) {
+ if (qstrcmp(options.at(j)->keyword, oldOptions[i].name) == 0) {
+ contains = true;
+ break;
+ }
+ }
+
+ if (!contains) {
+ newOptionCount = _cupsAddOption(oldOptions[i].name, oldOptions[i].value, newOptionCount, &newOptions);
+ }
+ }
+
+ // we can release old option list
+ _cupsFreeOptions(oldOptionCount, oldOptions);
+
+ // adding marked options
+ for (int i = 0; i < markedOptions.count(); ++i) {
+ const char* name = markedOptions.at(i);
+ ++i;
+ newOptionCount = _cupsAddOption(name, markedOptions.at(i), newOptionCount, &newOptions);
+ }
+
+ // placing the new option list
+ printers[currPrinterIndex].num_options = newOptionCount;
+ printers[currPrinterIndex].options = newOptions;
+
+ // saving new default values
+ _cupsSetDests(prnCount, printers);
+}
+
+QRect QCUPSSupport::paperRect(const char *choice) const
+{
+ if (!currPPD)
+ return QRect();
+ for (int i = 0; i < currPPD->num_sizes; ++i) {
+ if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
+ return QRect(0, 0, qRound(currPPD->sizes[i].width), qRound(currPPD->sizes[i].length));
+ }
+ return QRect();
+}
+
+QRect QCUPSSupport::pageRect(const char *choice) const
+{
+ if (!currPPD)
+ return QRect();
+ for (int i = 0; i < currPPD->num_sizes; ++i) {
+ if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
+ return QRect(qRound(currPPD->sizes[i].left),
+ qRound(currPPD->sizes[i].length - currPPD->sizes[i].top),
+ qRound(currPPD->sizes[i].right - currPPD->sizes[i].left),
+ qRound(currPPD->sizes[i].top - currPPD->sizes[i].bottom));
+ }
+ return QRect();
+}
+
+QStringList QCUPSSupport::options() const
+{
+ QStringList list;
+ collectMarkedOptions(list);
+ return list;
+}
+
+bool QCUPSSupport::printerHasPPD(const char *printerName)
+{
+ if (!isAvailable())
+ return false;
+ const char *ppdFile = _cupsGetPPD(printerName);
+ if (ppdFile)
+ unlink(ppdFile);
+ return (ppdFile != 0);
+}
+
+QString QCUPSSupport::unicodeString(const char *s)
+{
+#ifndef QT_NO_TEXTCODEC
+ return codec->toUnicode(s);
+#else
+ return QLatin1String(s);
+#endif
+}
+
+void QCUPSSupport::collectMarkedOptions(QStringList& list, const ppd_group_t* group) const
+{
+ if (group == 0) {
+ if (!currPPD)
+ return;
+ for (int i = 0; i < currPPD->num_groups; ++i) {
+ collectMarkedOptions(list, &currPPD->groups[i]);
+ collectMarkedOptionsHelper(list, &currPPD->groups[i]);
+ }
+ } else {
+ for (int i = 0; i < group->num_subgroups; ++i)
+ collectMarkedOptionsHelper(list, &group->subgroups[i]);
+ }
+}
+
+void QCUPSSupport::collectMarkedOptionsHelper(QStringList& list, const ppd_group_t* group) const
+{
+ for (int i = 0; i < group->num_options; ++i) {
+ for (int j = 0; j < group->options[i].num_choices; ++j) {
+ if (group->options[i].choices[j].marked == 1 && qstrcmp(group->options[i].choices[j].choice, group->options[i].defchoice) != 0)
+ list << QString::fromLocal8Bit(group->options[i].keyword) << QString::fromLocal8Bit(group->options[i].choices[j].choice);
+ }
+ }
+}
+
+QPair<int, QString> QCUPSSupport::tempFd()
+{
+ char filename[512];
+ int fd = _cupsTempFd(filename, 512);
+ return QPair<int, QString>(fd, QString::fromLocal8Bit(filename));
+}
+
+// Prints the given file and returns a job id.
+int QCUPSSupport::printFile(const char * printerName, const char * filename, const char * title,
+ int num_options, cups_option_t * options)
+{
+ return _cupsPrintFile(printerName, filename, title, num_options, options);
+}
+
+QCUPSSupport::Printer::Printer(const QString &n) : name(n), isDefault(false), cupsPrinterIndex(-1)
+{
+}
+
+QList<QCUPSSupport::Printer> QCUPSSupport::availableUnixPrinters()
+{
+ QList<Printer> printers;
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (QCUPSSupport::isAvailable()) {
+ QCUPSSupport cups;
+ int cupsPrinterCount = cups.availablePrintersCount();
+ const cups_dest_t* cupsPrinters = cups.availablePrinters();
+ for (int i = 0; i < cupsPrinterCount; ++i) {
+ QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name));
+ if (cupsPrinters[i].instance)
+ printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance);
+
+ Printer p(printerName);
+ if (cupsPrinters[i].is_default)
+ p.isDefault = true;
+ p.cupsPrinterIndex = i;
+ printers.append(p);
+ }
+ } else
+#endif
+ {
+ QList<QPrinterDescription> lprPrinters;
+ int defprn = qt_getLprPrinters(lprPrinters);
+ // populating printer combo
+ foreach (const QPrinterDescription &description, lprPrinters)
+ printers.append(Printer(description.name));
+ if (defprn >= 0 && defprn < printers.size())
+ printers[defprn].isDefault = true;
+ }
+
+ return printers;
+}
+
+QList<QPrinter::PaperSize> QCUPSSupport::getCupsPrinterPaperSizes(int cupsPrinterIndex)
+{
+ return qt_getCupsPrinterPaperSizes(cupsPrinterIndex);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_CUPS