source: trunk/src/gui/painting/qcups.cpp

Last change on this file was 1058, checked in by Dmitry A. Kuminov, 14 years ago

OS/2: Enable linking to cups.dll at runtime.

This requires CUPS 1.4.8 and above. Older versions will not
work anymore.

File size: 12.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41#include <qdebug.h>
42#include "qcups_p.h"
43
44#ifndef QT_NO_CUPS
45
46#ifndef QT_LINUXBASE // LSB merges everything into cups.h
47# include <cups/language.h>
48#endif
49#include <qtextcodec.h>
50
51QT_BEGIN_NAMESPACE
52
53typedef int (*CupsGetDests)(cups_dest_t **dests);
54typedef void (*CupsFreeDests)(int num_dests, cups_dest_t *dests);
55typedef const char* (*CupsGetPPD)(const char *printer);
56typedef int (*CupsMarkOptions)(ppd_file_t *ppd, int num_options, cups_option_t *options);
57typedef ppd_file_t* (*PPDOpenFile)(const char *filename);
58typedef void (*PPDMarkDefaults)(ppd_file_t *ppd);
59typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
60typedef void (*PPDClose)(ppd_file_t *ppd);
61typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
62typedef void (*CupsFreeOptions)(int num_options, cups_option_t *options);
63typedef void (*CupsSetDests)(int num_dests, cups_dest_t *dests);
64typedef cups_lang_t* (*CupsLangGet)(const char *language);
65typedef const char* (*CupsLangEncoding)(cups_lang_t *language);
66typedef int (*CupsAddOption)(const char *name, const char *value, int num_options, cups_option_t **options);
67typedef int (*CupsTempFd)(char *name, int len);
68typedef int (*CupsPrintFile)(const char * name, const char * filename, const char * title, int num_options, cups_option_t * options);
69
70static bool cupsLoaded = false;
71static int qt_cups_num_printers = 0;
72static CupsGetDests _cupsGetDests = 0;
73static CupsFreeDests _cupsFreeDests = 0;
74static CupsGetPPD _cupsGetPPD = 0;
75static PPDOpenFile _ppdOpenFile = 0;
76static PPDMarkDefaults _ppdMarkDefaults = 0;
77static PPDClose _ppdClose = 0;
78static CupsMarkOptions _cupsMarkOptions = 0;
79static PPDMarkOption _ppdMarkOption = 0;
80static CupsFreeOptions _cupsFreeOptions = 0;
81static CupsSetDests _cupsSetDests = 0;
82static CupsLangGet _cupsLangGet = 0;
83static CupsLangEncoding _cupsLangEncoding = 0;
84static CupsAddOption _cupsAddOption = 0;
85static CupsTempFd _cupsTempFd = 0;
86static CupsPrintFile _cupsPrintFile = 0;
87
88#ifdef Q_OS_OS2
89#define CUPS_RESOLVE_cups(func) _cups##func = (Cups##func) cupsLib.resolve("_cups"#func)
90#define CUPS_RESOLVE_ppd(func) _ppd##func = (PPD##func) cupsLib.resolve("_ppd"#func)
91#else
92#define CUPS_RESOLVE_cups(func) _cups##func = (Cups##func) cupsLib.resolve("cups"#func)
93#define CUPS_RESOLVE_ppd(func) _ppd##func = (PPD##func) cupsLib.resolve("ppd"#func)
94#endif
95
96static void resolveCups()
97{
98 QLibrary cupsLib(QLatin1String("cups"), 2);
99 if(cupsLib.load()) {
100 CUPS_RESOLVE_cups(GetDests);
101 CUPS_RESOLVE_cups(FreeDests);
102 CUPS_RESOLVE_cups(GetPPD);
103 CUPS_RESOLVE_cups(LangGet);
104 CUPS_RESOLVE_cups(LangEncoding);
105 CUPS_RESOLVE_ppd(OpenFile);
106 CUPS_RESOLVE_ppd(MarkDefaults);
107 CUPS_RESOLVE_ppd(Close);
108 CUPS_RESOLVE_cups(MarkOptions);
109 CUPS_RESOLVE_ppd(MarkOption);
110 CUPS_RESOLVE_cups(FreeOptions);
111 CUPS_RESOLVE_cups(SetDests);
112 CUPS_RESOLVE_cups(AddOption);
113 CUPS_RESOLVE_cups(TempFd);
114 CUPS_RESOLVE_cups(PrintFile);
115
116 if (_cupsGetDests && _cupsFreeDests) {
117 cups_dest_t *printers;
118 int num_printers = _cupsGetDests(&printers);
119 if (num_printers)
120 _cupsFreeDests(num_printers, printers);
121 qt_cups_num_printers = num_printers;
122 }
123 }
124 cupsLoaded = true;
125}
126
127// ================ CUPS Support class ========================
128
129QCUPSSupport::QCUPSSupport()
130 :
131 prnCount(0),
132 printers(0),
133 page_sizes(0),
134 currPrinterIndex(0),
135 currPPD(0)
136{
137 if (!cupsLoaded)
138 resolveCups();
139
140 // getting all available printers
141 if (!isAvailable())
142 return;
143
144 prnCount = _cupsGetDests(&printers);
145
146 for (int i = 0; i < prnCount; ++i) {
147 if (printers[i].is_default) {
148 currPrinterIndex = i;
149 setCurrentPrinter(i);
150 break;
151 }
152 }
153
154#ifndef QT_NO_TEXTCODEC
155 cups_lang_t *cupsLang = _cupsLangGet(0);
156 codec = QTextCodec::codecForName(_cupsLangEncoding(cupsLang));
157 if (!codec)
158 codec = QTextCodec::codecForLocale();
159#endif
160}
161
162QCUPSSupport::~QCUPSSupport()
163{
164 if (currPPD)
165 _ppdClose(currPPD);
166 if (prnCount)
167 _cupsFreeDests(prnCount, printers);
168}
169
170int QCUPSSupport::availablePrintersCount() const
171{
172 return prnCount;
173}
174
175const cups_dest_t* QCUPSSupport::availablePrinters() const
176{
177 return printers;
178}
179
180const ppd_file_t* QCUPSSupport::currentPPD() const
181{
182 return currPPD;
183}
184
185const ppd_file_t* QCUPSSupport::setCurrentPrinter(int index)
186{
187 Q_ASSERT(index >= 0 && index <= prnCount);
188 if (index == prnCount)
189 return 0;
190
191 currPrinterIndex = index;
192
193 if (currPPD)
194 _ppdClose(currPPD);
195 currPPD = 0;
196 page_sizes = 0;
197
198 const char *ppdFile = _cupsGetPPD(printers[index].name);
199
200 if (!ppdFile)
201 return 0;
202
203 currPPD = _ppdOpenFile(ppdFile);
204 unlink(ppdFile);
205
206 // marking default options
207 _ppdMarkDefaults(currPPD);
208
209 // marking options explicitly set
210 _cupsMarkOptions(currPPD, printers[currPrinterIndex].num_options, printers[currPrinterIndex].options);
211
212 // getting pointer to page sizes
213 page_sizes = ppdOption("PageSize");
214
215 return currPPD;
216}
217
218int QCUPSSupport::currentPrinterIndex() const
219{
220 return currPrinterIndex;
221}
222
223bool QCUPSSupport::isAvailable()
224{
225 if(!cupsLoaded)
226 resolveCups();
227
228 return
229 _cupsGetDests &&
230 _cupsFreeDests &&
231 _cupsGetPPD &&
232 _ppdOpenFile &&
233 _ppdMarkDefaults &&
234 _ppdClose &&
235 _cupsMarkOptions &&
236 _ppdMarkOption &&
237 _cupsFreeOptions &&
238 _cupsSetDests &&
239 _cupsLangGet &&
240 _cupsLangEncoding &&
241 _cupsAddOption &&
242 (qt_cups_num_printers > 0);
243}
244
245const ppd_option_t* QCUPSSupport::ppdOption(const char *key) const
246{
247 if (currPPD) {
248 for (int gr = 0; gr < currPPD->num_groups; ++gr) {
249 for (int opt = 0; opt < currPPD->groups[gr].num_options; ++opt) {
250 if (qstrcmp(currPPD->groups[gr].options[opt].keyword, key) == 0)
251 return &currPPD->groups[gr].options[opt];
252 }
253 }
254 }
255 return 0;
256}
257
258const cups_option_t* QCUPSSupport::printerOption(const QString &key) const
259{
260 for (int i = 0; i < printers[currPrinterIndex].num_options; ++i) {
261 if (QLatin1String(printers[currPrinterIndex].options[i].name) == key)
262 return &printers[currPrinterIndex].options[i];
263 }
264 return 0;
265}
266
267const ppd_option_t* QCUPSSupport::pageSizes() const
268{
269 return page_sizes;
270}
271
272int QCUPSSupport::markOption(const char* name, const char* value)
273{
274 return _ppdMarkOption(currPPD, name, value);
275}
276
277void QCUPSSupport::saveOptions(QList<const ppd_option_t*> options, QList<const char*> markedOptions)
278{
279 int oldOptionCount = printers[currPrinterIndex].num_options;
280 cups_option_t* oldOptions = printers[currPrinterIndex].options;
281
282 int newOptionCount = 0;
283 cups_option_t* newOptions = 0;
284
285 // copying old options that are not on the new list
286 for (int i = 0; i < oldOptionCount; ++i) {
287 bool contains = false;
288 for (int j = 0; j < options.count(); ++j) {
289 if (qstrcmp(options.at(j)->keyword, oldOptions[i].name) == 0) {
290 contains = true;
291 break;
292 }
293 }
294
295 if (!contains) {
296 newOptionCount = _cupsAddOption(oldOptions[i].name, oldOptions[i].value, newOptionCount, &newOptions);
297 }
298 }
299
300 // we can release old option list
301 _cupsFreeOptions(oldOptionCount, oldOptions);
302
303 // adding marked options
304 for (int i = 0; i < markedOptions.count(); ++i) {
305 const char* name = markedOptions.at(i);
306 ++i;
307 newOptionCount = _cupsAddOption(name, markedOptions.at(i), newOptionCount, &newOptions);
308 }
309
310 // placing the new option list
311 printers[currPrinterIndex].num_options = newOptionCount;
312 printers[currPrinterIndex].options = newOptions;
313
314 // saving new default values
315 _cupsSetDests(prnCount, printers);
316}
317
318QRect QCUPSSupport::paperRect(const char *choice) const
319{
320 if (!currPPD)
321 return QRect();
322 for (int i = 0; i < currPPD->num_sizes; ++i) {
323 if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
324 return QRect(0, 0, qRound(currPPD->sizes[i].width), qRound(currPPD->sizes[i].length));
325 }
326 return QRect();
327}
328
329QRect QCUPSSupport::pageRect(const char *choice) const
330{
331 if (!currPPD)
332 return QRect();
333 for (int i = 0; i < currPPD->num_sizes; ++i) {
334 if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
335 return QRect(qRound(currPPD->sizes[i].left),
336 qRound(currPPD->sizes[i].length - currPPD->sizes[i].top),
337 qRound(currPPD->sizes[i].right - currPPD->sizes[i].left),
338 qRound(currPPD->sizes[i].top - currPPD->sizes[i].bottom));
339 }
340 return QRect();
341}
342
343QStringList QCUPSSupport::options() const
344{
345 QStringList list;
346 collectMarkedOptions(list);
347 return list;
348}
349
350bool QCUPSSupport::printerHasPPD(const char *printerName)
351{
352 if (!isAvailable())
353 return false;
354 const char *ppdFile = _cupsGetPPD(printerName);
355 if (ppdFile)
356 unlink(ppdFile);
357 return (ppdFile != 0);
358}
359
360QString QCUPSSupport::unicodeString(const char *s)
361{
362#ifndef QT_NO_TEXTCODEC
363 return codec->toUnicode(s);
364#else
365 return QLatin1String(s);
366#endif
367}
368
369void QCUPSSupport::collectMarkedOptions(QStringList& list, const ppd_group_t* group) const
370{
371 if (group == 0) {
372 if (!currPPD)
373 return;
374 for (int i = 0; i < currPPD->num_groups; ++i) {
375 collectMarkedOptions(list, &currPPD->groups[i]);
376 collectMarkedOptionsHelper(list, &currPPD->groups[i]);
377 }
378 } else {
379 for (int i = 0; i < group->num_subgroups; ++i)
380 collectMarkedOptionsHelper(list, &group->subgroups[i]);
381 }
382}
383
384void QCUPSSupport::collectMarkedOptionsHelper(QStringList& list, const ppd_group_t* group) const
385{
386 for (int i = 0; i < group->num_options; ++i) {
387 for (int j = 0; j < group->options[i].num_choices; ++j) {
388 if (group->options[i].choices[j].marked == 1 && qstrcmp(group->options[i].choices[j].choice, group->options[i].defchoice) != 0)
389 list << QString::fromLocal8Bit(group->options[i].keyword) << QString::fromLocal8Bit(group->options[i].choices[j].choice);
390 }
391 }
392}
393
394QPair<int, QString> QCUPSSupport::tempFd()
395{
396 char filename[512];
397 int fd = _cupsTempFd(filename, 512);
398 return QPair<int, QString>(fd, QString::fromLocal8Bit(filename));
399}
400
401// Prints the given file and returns a job id.
402int QCUPSSupport::printFile(const char * printerName, const char * filename, const char * title,
403 int num_options, cups_option_t * options)
404{
405 return _cupsPrintFile(printerName, filename, title, num_options, options);
406}
407
408QT_END_NAMESPACE
409
410#endif // QT_NO_CUPS
Note: See TracBrowser for help on using the repository browser.