[Development] Adding CPD support to Qt print dialog

Till Kamppeter till.kamppeter at gmail.com
Mon Sep 19 12:38:14 CEST 2022

On 16/09/2022 08:32, Shawn Rutledge wrote:
> Along with Chris, I’m wondering why you think it should be a plugin.
> Anyway it seems some misunderstandings are possible.  Lars wrote "code 
> that uses the CPDB dialogs instead of our own implementations”… but are 
> there replacement GUI dialogs? The web site says it’s about "separating 
> the print dialogs of different GUI toolkits and applications (GTK, Qt, 
> LibreOffice, …) from the different print technologies (CUPS/IPP, Google 
> Cloud Print, …) so that they can get developed independently”.  And they 
> use D-Bus.  Here are the current D-Bus specifications (which have been 
> modified recently): 
> https://github.com/OpenPrinting/cpdb-libs/tree/master/cpdb/interface 
> <https://github.com/OpenPrinting/cpdb-libs/tree/master/cpdb/interface> So now 
> it seems we bump into the typical GTK/glib pattern that they like to 
> provide a stable C interface, as a higher priority than a 
> stable D-Bus interface.  But Qt has its own D-Bus implementation, so we 
> tend to prefer using that, rather than using some external library that 
> uses some other library that talks to D-Bus.  But if you really want to 
> use the library, maybe /that/ could be a reason to do dynamic loading?

First, as I told already in my answer to Lars' post in this thread, we 
do not create a new print dialog, no GUI design and change needed. We 
only change the method how the already existing Qt dialog obtains 
available printers, their cpabilities and options, and send print jobs. 
We move the communication with the print technologies (CUPS, 
print-to-file, cloud printing, ...) into separate D-Bus-coupled modules 
which get maintained by the maintainers of each print technology, 
removing the burden of keeping the print dialogs up-to-date with changes 
in the print technologies from the GUI toolkit developers.

The CPDB frontend library in the cpdb-libs package contains a D-Bus 
interface to communicate with the modules (the backends) and an API for 
the print dialogs (the frontends) on its other end.

The easiest way to obtain CPDB support in a print dialog is just using 
cpdb-libs, not caring about what the library does internally (in our 
case using D-Bus). This is also the safest way to keep everything 
working should the internals of CPDB change (modifications in the D-Bus 
interface or even replacing the D-Bus connection by something completely 

The problem that cpdb-libs and Qt use different D-Bus 
implementations/libraries is best to overcome by having the CPDB support 
in a dynamically loaded Qt print backend and not directly in the Qt dialog.

A re-implementation of the frontend part of CPDB with Qt's D-Bus 
implementation to overcome the need of two different libraries for D-Bus 
access in the whole Qt print dialog would lead to a maintenance 
overhead. Any change in the D-Bus interface in the original OpenPrinting 
implementation needs to get reflected in the Qt implementation.

> On most Linux distros, Qt gets installed as normal packages, so it’s up 
> to the packagers to ensure that Qt’s dependencies shall be installed as 
> pre-requisites.  In that case, if it ends up that cpdb-lib is a 
> dependency, and it gets installed automatically, that’s fine.

Linux distros are not such a problem. They will come with cpdb-libs and 
auto-install it if an installed print dialog or app needs it.

> But 
> commercial applications, and applications on other operating systems, 
> tend to get developed with a version of Qt that comes from the Qt 
> installer, so then dependency management is trickier, and we sometimes 
> use dynamic loading of “iffy” libraries that may or may not already be 
> installed.  (But if CPDB really becomes universal, then maybe within a 
> few years we could assume that it’s always installed.)

Yes, here dynamic loading would be the solution, either cpdb-libs itself 
or the CPDB Qt print backend.

Sandboxed packages, like Snaps, must contain cpdb-libs to support CPDB, 
and they must be set to allowthe encapsulated application to access the 
host systems D-Bus.

> If you’d develop with Qt D-Bus https://doc.qt.io/qt-6/qtdbus-index.html 
> <https://doc.qt.io/qt-6/qtdbus-index.html> you would not have a library 
> dependency problem; but instead, you’d have the problem that the D-Bus 
> interface for this service may change, that requires maintenance, and 
> someone has to follow along with the changes that are being done in 
> cpdb-lib, so that our implementation keeps working like theirs does. 
>   But so far, we are getting away with this approach in other cases, 
> such as the AppMenu and StatusNotifier interfaces.  So I think I’d still 
> try to do it that way; I just hope they don't break compatibility often. 
>   GTK/glib people may say they want to be able to break compatibility at 
> any time, but to me it doesn’t make sense to say that an interface 
> /specification/ is more fluid than a C interface that implements it. 
>   The XML has to be published and versioned.  When it’s stable, both the 
> C and D-Bus interfaces stop changing.  And if the world treats the D-Bus 
> interface as being stable, they may feel some drag, and be reluctant to 
> break compatibility; IMO that’s as it should be.

If we use cpdb-libs to provide the D-Bus interface we have in fact much 
lower maintenance overhead, as we only need to keep pace with changes in 
the glib D-Bus implementation and not with both glib and Qt, but we 
always have the dependency on glib.

> So my assumption is you don’t necessarily have to modify the design of 
> QPrintDialog much, or replace it with another dialog, but rather that 
> there will be a new way of populating the printers there, getting their 
> capabilities, starting print jobs and so on; is that right?  If that's 
> not true, and actually you need a different UI design, then yeah maybe 
> it becomes tricky to have two kinds of print dialogs, or maybe it’s 
> better to implement a Qt Quick version first.

No new UI design needed, as I said earlier here and in the answer to 
Lars' post.

> OK so what happened last time: 
> https://openprinting.github.io/gsoc2020/02-common-print-dialog/ 
> <https://openprinting.github.io/gsoc2020/02-common-print-dialog/> 
> https://github.com/rithvikp1998/CPDv2/blob/master/common-print-dialog.pro <https://github.com/rithvikp1998/CPDv2/blob/master/common-print-dialog.pro> nope 
> there’s no Qt D-Bus there, they linked with gio-unix-2.0 glib-2.0 
> gobject-2.0 cpdb-libs-frontend

Yes, there was no discussion about using Qt's own implementation of 
D-Bus access, I even was not aware of that.

> Another aspect that I haven’t kept up with very well is how 
> containerized applications should do printing.  We have “portal” support 
> for file dialogs, for example, but is CPDB intended to work the same way 
> regardless whether the app has such security restrictions or not?  For 
> that matter, as a design principle, is everyone still sure that the 
> way for an application to reach outside its container is D-Bus 
> interfaces that are designed to be trusted? 
> https://blogs.gnome.org/mclasen/2018/07/19/flatpak-a-look-behind-the-portal/ 
> <https://blogs.gnome.org/mclasen/2018/07/19/flatpak-a-look-behind-the-portal/>

Flatpak uses portals, the containerized desktop GUI app does not use its 
own Open/Save as/Print dialogs but calls the ones of the hosts desktop 
environment (KDE/GNOME) via D-Bus. Snap adds AppArmor rules to permit 
access to defined host system facilities, or it mounts file systems of 
the host system or of other Snaps. One can open host D-Bus access by 
using an appropriate Snap interface,

What could theoretically happen is that a malicious CPDB backend is 
created which provides faked printers, but it is the same risk both if a 
Faltpaked app calls the desktop's print dialog via portal or if a 
snapped application's own, CPDB-enabled dialog accesses the malicious 
backend through Snap's D-Bus interface.

A protection measure would be that the CPDB backend modules are 
root-owned (but not necessarily need to run as root), so that non-root 
users cannot simply add new backends.

> We still don’t have a print dialog in Qt Quick Dialogs, and I think we 
> need to add one within the next couple of years (if we get around to 
> defining how printing is supposed to work; I have a reasonable idea for 
> that, I think, but nobody has implemented anything like that AFAIK).  So 
> we do need a nice interface, suited to implementing that kind of dialog. 

And what is the print dialog we see opened by Qt/KDE apps then? Where 
does it come from?

>   I don’t see any “dialog helpers” for print dialogs yet; 
> qtbase/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h doesn’t have 
> a GTK print dialog.  Other Qt Quick Dialogs like 
> https://doc.qt.io/qt-6/qml-qtquick-dialogs-filedialog.html 
> <https://doc.qt.io/qt-6/qml-qtquick-dialogs-filedialog.html> use such 
> helpers to show native platform dialogs, and we also have QML/Qt Quick 
> Controls implementations of the same dialogs that are designed to look 
> like (or better than) the widget dialogs.  (A Qt Quick application 
> should never need to load the widget library, for any of its 
> functionality.  That’s a goal… not always achieved so far. 
> https://doc.qt.io/qt-6/qtlabsplatform-index.html 
> <https://doc.qt.io/qt-6/qtlabsplatform-index.html> exists for the few 
> cases when widgets are still needed, and we are actively trying to 
> shrink that module by finding ways to implement the same functionality 
> without widget dependencies.)
> So I think there are several areas to start work in:
> - a Qt D-Bus implementation of the CPDB interface

Probably the simplest to overcome the glib-D-Bus library overhead.

> - add code to src/printsupport/dialogs/qprintdialog_unix.cpp to use that 
> D-Bus implementation (wrapped with #if QT_CONFIG(cpdb) or whatever, and 
> without removing other functionality for now)

What do you mean here exactly? Using cpdb-libs with its D-Bus access if 
the code enclosed by #if QT_CONFIG(cpdb) is used?

> - some QPA abstraction that a QML-implemented PrintDialog can use: that 
> probably includes a QAbstractItemModel or QAbstractListModel subclass 
> for the list of printers, maybe another model for the choices that a 
> particular printer can present to the user, and so on
> - add the GTK print dialog helper; that’s unrelated to the rest, but 
> when we add a QML PrintDialog, we may want to have the usual “native 
> dialog” alternative; and perhaps it already uses CPDB?  Users of Gnome 
> and other GTK-based desktops will expect it, but almost nobody else.

Does this mean that we make the Qt/KDE apps use the GTK print dialog for 
which Gaurav has already done the CPDB support? Would be a lot of 
library overhead for pure KDE/Qt distros or for containerized apps.

> - add print dialog helpers to all other platforms where it’s possible 
> (macOS, Windows, iOS/iPadOS, Android, …?)

We need CPDB only for Linux and similar OSes not for 

> - work with KDE, sync up with their approach to this

Our CPDB support should work in all Qt apps not only in KDE apps.

> I suppose for GSoC, probably it’s just the first two that are in scope, 
> that’s fine.  For the first one, there is a well-defined process, so 
> don’t be afraid of it.

Gaurav, perhaps you should start here then.

> You might get a first pass done in a few days, 
> and I’m willing to help you figure it out if necessary.  Both of those 
> tasks could result in patches that you can submit to 
> codereview.qt-project.org <http://codereview.qt-project.org> and then we 
> will have support for this new D-Bus interface.  (I could be wrong, 
> since I haven’t tried to implement this.  But it seems worth a try, at 
> least.)

Gaurav, could you do these steps?


More information about the Development mailing list