1 // This is the implementation of the QPyDBusReply class.
2 //
3 // Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of PyQt5.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file.  Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license.  For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 
20 
21 #include <Python.h>
22 
23 #include <QDBusMessage>
24 #include <QDBusPendingCall>
25 
26 #include "qpydbusreply.h"
27 
28 #include "sipAPIQtDBus.h"
29 
30 
31 // Extract a reply from a message.  The GIL should be held.
QPyDBusReply(const QDBusMessage & reply)32 QPyDBusReply::QPyDBusReply(const QDBusMessage &reply)
33 {
34     *this = reply;
35 }
36 
37 
38 // Extract a reply from a pending call.  The GIL should be held.
QPyDBusReply(const QDBusPendingCall & call)39 QPyDBusReply::QPyDBusReply(const QDBusPendingCall &call)
40 {
41     *this = call;
42 }
43 
44 
45 // Extract a reply from an error.
QPyDBusReply(const QDBusError & error)46 QPyDBusReply::QPyDBusReply(const QDBusError &error)
47 {
48     _q_value = 0;
49     _q_is_valid = !error.isValid();
50     _q_error = error;
51 }
52 
53 
54 // Copy a reply.  The GIL should be held.
QPyDBusReply(const QPyDBusReply & other)55 QPyDBusReply::QPyDBusReply(const QPyDBusReply &other)
56 {
57     _q_value = other._q_value;
58     Py_XINCREF(_q_value);
59 
60     _q_value_variant = other._q_value_variant;
61     _q_is_valid = other._q_is_valid;
62     _q_error = other._q_error;
63 }
64 
65 
66 // A reply created from a QDBusReply<> mapped type convertor.
QPyDBusReply(PyObject * q_value,bool q_is_valid,const QDBusError & q_error)67 QPyDBusReply::QPyDBusReply(PyObject *q_value, bool q_is_valid, const QDBusError &q_error) : _q_value(q_value), _q_is_valid(q_is_valid), _q_error(q_error)
68 {
69 }
70 
71 
72 // The dtor.  The GIL should be held.
~QPyDBusReply()73 QPyDBusReply::~QPyDBusReply()
74 {
75     Py_XDECREF(_q_value);
76 }
77 
78 
79 // Return the value of the reply.  The GIL should be held.
value(PyObject * type) const80 PyObject *QPyDBusReply::value(PyObject *type) const
81 {
82     if (!_q_is_valid)
83     {
84         PyErr_SetString(PyExc_ValueError, "QDBusReply value is invalid");
85         return 0;
86     }
87 
88     // Return any explicit value.
89     if (_q_value)
90     {
91         if (type)
92         {
93             PyErr_SetString(PyExc_ValueError,
94                     "'type' argument cannot be used with an explcitly typed reply");
95             return 0;
96         }
97 
98         Py_INCREF(_q_value);
99         return _q_value;
100     }
101 
102     QVariant val(_q_value_variant);
103 
104     return pyqt5_qtdbus_from_qvariant_by_type(val, type);
105 }
106 
107 
108 // Extract a reply from a message.  The GIL should be held.
operator =(const QDBusMessage & reply)109 QPyDBusReply &QPyDBusReply::operator=(const QDBusMessage &reply)
110 {
111     _q_value = 0;
112     _q_error = reply;
113     _q_is_valid = !_q_error.isValid();
114 
115     if (_q_is_valid)
116     {
117         QList<QVariant> results = reply.arguments();
118 
119         if (results.count() == 0)
120         {
121             Py_INCREF(Py_None);
122             _q_value = Py_None;
123         }
124         else
125         {
126             // Convert this later if requested.
127             _q_value_variant = results.at(0);
128         }
129     }
130 
131     return *this;
132 }
133 
134 
135 // Extract a reply from a pending call.  The GIL should be held.
operator =(const QDBusPendingCall & call)136 QPyDBusReply &QPyDBusReply::operator=(const QDBusPendingCall &call)
137 {
138     QDBusPendingCall other(call);
139 
140     Py_BEGIN_ALLOW_THREADS
141     other.waitForFinished();
142     Py_END_ALLOW_THREADS
143 
144     return *this = other.reply();
145 }
146