1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the examples of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** BSD License Usage |
18 | ** Alternatively, you may use this file under the terms of the BSD license |
19 | ** as follows: |
20 | ** |
21 | ** "Redistribution and use in source and binary forms, with or without |
22 | ** modification, are permitted provided that the following conditions are |
23 | ** met: |
24 | ** * Redistributions of source code must retain the above copyright |
25 | ** notice, this list of conditions and the following disclaimer. |
26 | ** * Redistributions in binary form must reproduce the above copyright |
27 | ** notice, this list of conditions and the following disclaimer in |
28 | ** the documentation and/or other materials provided with the |
29 | ** distribution. |
30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
31 | ** contributors may be used to endorse or promote products derived |
32 | ** from this software without specific prior written permission. |
33 | ** |
34 | ** |
35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
46 | ** |
47 | ** $QT_END_LICENSE$ |
48 | ** |
49 | ****************************************************************************/ |
50 | |
51 | #include "dialog.h" |
52 | #include <QFileDialog> |
53 | #include <QBuffer> |
54 | |
55 | /*! |
56 | \class Dialog |
57 | |
58 | \brief This class is a simple example of how to use QSharedMemory. |
59 | |
60 | It is a simple dialog that presents a few buttons. To compile the |
61 | example, run make in qt/examples/ipc. Then run the executable twice |
62 | to create two processes running the dialog. In one of the processes, |
63 | press the button to load an image into a shared memory segment, and |
64 | then select an image file to load. Once the first process has loaded |
65 | and displayed the image, in the second process, press the button to |
66 | read the same image from shared memory. The second process displays |
67 | the same image loaded from its new loaction in shared memory. |
68 | */ |
69 | |
70 | /*! |
71 | The class contains a data member \l {QSharedMemory} {sharedMemory}, |
72 | which is initialized with the key "QSharedMemoryExample" to force |
73 | all instances of Dialog to access the same shared memory segment. |
74 | The constructor also connects the clicked() signal from each of the |
75 | three dialog buttons to the slot function appropriate for handling |
76 | each button. |
77 | */ |
78 | //! [0] |
79 | Dialog::Dialog(QWidget *parent) |
80 | : QDialog(parent), sharedMemory("QSharedMemoryExample" ) |
81 | { |
82 | ui.setupUi(this); |
83 | connect(sender: ui.loadFromFileButton, signal: &QPushButton::clicked, |
84 | receiver: this, slot: &Dialog::loadFromFile); |
85 | connect(sender: ui.loadFromSharedMemoryButton, signal: &QPushButton::clicked, |
86 | receiver: this, slot: &Dialog::loadFromMemory); |
87 | setWindowTitle(tr(s: "SharedMemory Example" )); |
88 | } |
89 | //! [0] |
90 | |
91 | /*! |
92 | This slot function is called when the \tt {Load Image From File...} |
93 | button is pressed on the firs Dialog process. First, it tests |
94 | whether the process is already connected to a shared memory segment |
95 | and, if so, detaches from that segment. This ensures that we always |
96 | start the example from the beginning if we run it multiple times |
97 | with the same two Dialog processes. After detaching from an existing |
98 | shared memory segment, the user is prompted to select an image file. |
99 | The selected file is loaded into a QImage. The QImage is displayed |
100 | in the Dialog and streamed into a QBuffer with a QDataStream. |
101 | |
102 | Next, it gets a new shared memory segment from the system big enough |
103 | to hold the image data in the QBuffer, and it locks the segment to |
104 | prevent the second Dialog process from accessing it. Then it copies |
105 | the image from the QBuffer into the shared memory segment. Finally, |
106 | it unlocks the shared memory segment so the second Dialog process |
107 | can access it. |
108 | |
109 | After this function runs, the user is expected to press the \tt |
110 | {Load Image from Shared Memory} button on the second Dialog process. |
111 | |
112 | \sa loadFromMemory() |
113 | */ |
114 | //! [1] |
115 | void Dialog::loadFromFile() |
116 | { |
117 | if (sharedMemory.isAttached()) |
118 | detach(); |
119 | |
120 | ui.label->setText(tr(s: "Select an image file" )); |
121 | QString fileName = QFileDialog::getOpenFileName(parent: 0, caption: QString(), dir: QString(), |
122 | filter: tr(s: "Images (*.png *.xpm *.jpg)" )); |
123 | QImage image; |
124 | if (!image.load(fileName)) { |
125 | ui.label->setText(tr(s: "Selected file is not an image, please select another." )); |
126 | return; |
127 | } |
128 | ui.label->setPixmap(QPixmap::fromImage(image)); |
129 | //! [1] //! [2] |
130 | |
131 | // load into shared memory |
132 | QBuffer buffer; |
133 | buffer.open(openMode: QBuffer::ReadWrite); |
134 | QDataStream out(&buffer); |
135 | out << image; |
136 | int size = buffer.size(); |
137 | |
138 | if (!sharedMemory.create(size)) { |
139 | ui.label->setText(tr(s: "Unable to create shared memory segment." )); |
140 | return; |
141 | } |
142 | sharedMemory.lock(); |
143 | char *to = (char*)sharedMemory.data(); |
144 | const char *from = buffer.data().data(); |
145 | memcpy(dest: to, src: from, n: qMin(a: sharedMemory.size(), b: size)); |
146 | sharedMemory.unlock(); |
147 | } |
148 | //! [2] |
149 | |
150 | /*! |
151 | This slot function is called in the second Dialog process, when the |
152 | user presses the \tt {Load Image from Shared Memory} button. First, |
153 | it attaches the process to the shared memory segment created by the |
154 | first Dialog process. Then it locks the segment for exclusive |
155 | access, copies the image data from the segment into a QBuffer, and |
156 | streams the QBuffer into a QImage. Then it unlocks the shared memory |
157 | segment, detaches from it, and finally displays the QImage in the |
158 | Dialog. |
159 | |
160 | \sa loadFromFile() |
161 | */ |
162 | //! [3] |
163 | void Dialog::loadFromMemory() |
164 | { |
165 | if (!sharedMemory.attach()) { |
166 | ui.label->setText(tr(s: "Unable to attach to shared memory segment.\n" \ |
167 | "Load an image first." )); |
168 | return; |
169 | } |
170 | |
171 | QBuffer buffer; |
172 | QDataStream in(&buffer); |
173 | QImage image; |
174 | |
175 | sharedMemory.lock(); |
176 | buffer.setData(adata: (char*)sharedMemory.constData(), alen: sharedMemory.size()); |
177 | buffer.open(openMode: QBuffer::ReadOnly); |
178 | in >> image; |
179 | sharedMemory.unlock(); |
180 | |
181 | sharedMemory.detach(); |
182 | ui.label->setPixmap(QPixmap::fromImage(image)); |
183 | } |
184 | //! [3] |
185 | |
186 | /*! |
187 | This private function is called by the destructor to detach the |
188 | process from its shared memory segment. When the last process |
189 | detaches from a shared memory segment, the system releases the |
190 | shared memory. |
191 | */ |
192 | void Dialog::detach() |
193 | { |
194 | if (!sharedMemory.detach()) |
195 | ui.label->setText(tr(s: "Unable to detach from shared memory." )); |
196 | } |
197 | |
198 | |