LibreOffice Module extensions (master) 1
scanunx.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include "scanner.hxx"
21#include "sanedlg.hxx"
22#include <o3tl/safeint.hxx>
23#include <osl/thread.hxx>
24#include <sal/log.hxx>
25#include <utility>
26#include <vcl/svapp.hxx>
27#include <memory>
28
29#include <com/sun/star/scanner/ScannerException.hpp>
30
32{
33 SAL_INFO("extensions.scanner", "BitmapTransporter");
34}
35
36
38{
39 SAL_INFO("extensions.scanner", "~BitmapTransporter");
40}
41
42
44{
45 osl::MutexGuard aGuard( m_aProtector );
46 css::awt::Size aRet;
47
48 // ensure that there is at least a header
49 int nLen = m_aStream.TellEnd();
50 if( nLen > 15 )
51 {
52 int nPreviousPos = m_aStream.Tell();
53 m_aStream.Seek( 4 );
54 m_aStream.ReadInt32( aRet.Width ).ReadInt32( aRet.Height );
55 m_aStream.Seek( nPreviousPos );
56 }
57 else
58 aRet.Width = aRet.Height = 0;
59
60
61 return aRet;
62}
63
64
66{
67 osl::MutexGuard aGuard( m_aProtector );
68 int nPreviousPos = m_aStream.Tell();
69
70 // create return value
71 int nBytes = m_aStream.TellEnd();
72 m_aStream.Seek( 0 );
73
74 Sequence< sal_Int8 > aValue( nBytes );
75 m_aStream.ReadBytes( aValue.getArray(), nBytes );
76 m_aStream.Seek( nPreviousPos );
77
78 return aValue;
79}
80
81namespace {
82
83struct SaneHolder
84{
85 Sane m_aSane;
87 osl::Mutex m_aProtector;
88 ScanError m_nError;
89 bool m_bBusy;
90
91 SaneHolder() : m_nError(ScanError_ScanErrorNone), m_bBusy(false) {}
92};
93
94 typedef std::vector< std::shared_ptr<SaneHolder> > sanevec;
95 class allSanes
96 {
97 private:
98 int mnRefCount;
99 public:
100 sanevec m_aSanes;
101 allSanes() : mnRefCount(0) {}
102 void acquire();
103 void release();
104 };
105
106 void allSanes::acquire()
107 {
108 ++mnRefCount;
109 }
110
111 void allSanes::release()
112 {
113 // was unused, now because of i99835: "Scanning interface not SANE API
114 // compliant" destroy all SaneHolder to get Sane Dtor called
115 --mnRefCount;
116 if (!mnRefCount)
117 m_aSanes.clear();
118 }
119
120 struct theSaneProtector : public rtl::Static<osl::Mutex, theSaneProtector> {};
121 struct theSanes : public rtl::Static<allSanes, theSanes> {};
122
123class ScannerThread : public osl::Thread
124{
125 std::shared_ptr<SaneHolder> m_pHolder;
127 ScannerManager* m_pManager; // just for the disposing call
128
129public:
130 virtual void SAL_CALL run() override;
131 virtual void SAL_CALL onTerminated() override { delete this; }
132public:
133 ScannerThread( std::shared_ptr<SaneHolder> pHolder,
135 ScannerManager* pManager );
136 virtual ~ScannerThread() override;
137};
138
139}
140
141ScannerThread::ScannerThread(std::shared_ptr<SaneHolder> pHolder,
143 ScannerManager* pManager)
144 : m_pHolder(std::move( pHolder )), m_xListener( listener ), m_pManager( pManager )
145{
146 SAL_INFO("extensions.scanner", "ScannerThread");
147}
148
149
150ScannerThread::~ScannerThread()
151{
152 SAL_INFO("extensions.scanner", "~ScannerThread");
153}
154
155
156void ScannerThread::run()
157{
158 osl_setThreadName("ScannerThread");
159
160 osl::MutexGuard aGuard( m_pHolder->m_aProtector );
162
163 m_pHolder->m_xBitmap = pTransporter;
164
165 m_pHolder->m_bBusy = true;
166 if( m_pHolder->m_aSane.IsOpen() )
167 {
168 int nOption = m_pHolder->m_aSane.GetOptionByName( "preview" );
169 if( nOption != -1 )
170 m_pHolder->m_aSane.SetOptionValue( nOption, false );
171
172 m_pHolder->m_nError =
173 m_pHolder->m_aSane.Start( *pTransporter ) ?
174 ScanError_ScanErrorNone : ScanError_ScanCanceled;
175 }
176 else
177 m_pHolder->m_nError = ScanError_ScannerNotAvailable;
178
179
180 Reference< XInterface > xXInterface( static_cast< OWeakObject* >( m_pManager ) );
181 m_xListener->disposing( css::lang::EventObject(xXInterface) );
182 m_pHolder->m_bBusy = false;
183}
184
185
187{
188 osl::MutexGuard aGuard( theSaneProtector::get() );
189 theSanes::get().acquire();
190}
191
192
194{
195 osl::MutexGuard aGuard( theSaneProtector::get() );
196 theSanes::get().release();
197}
198
199
201{
202 css::awt::Size aRet;
203 aRet.Width = aRet.Height = 0;
204 return aRet;
205}
206
207
209{
210 return Sequence< sal_Int8 >();
211}
212
213
215{
216 osl::MutexGuard aGuard( theSaneProtector::get() );
217 sanevec &rSanes = theSanes::get().m_aSanes;
218
219 if( rSanes.empty() )
220 {
221 auto pSaneHolder = std::make_shared<SaneHolder>();
222 if( Sane::IsSane() )
223 rSanes.push_back( pSaneHolder );
224 }
225
226 if( Sane::IsSane() )
227 {
228 Sequence< ScannerContext > aRet{ { /* ScannerName */ "SANE", /* InternalData */ 0 } };
229 return aRet;
230 }
231
233}
234
235
236sal_Bool ScannerManager::configureScannerAndScan( ScannerContext& scanner_context,
238{
239 bool bRet;
240 bool bScan;
241 {
242 osl::MutexGuard aGuard( theSaneProtector::get() );
243 sanevec &rSanes = theSanes::get().m_aSanes;
244
245 SAL_INFO("extensions.scanner", "ScannerManager::configureScanner");
246
247 if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() )
248 throw ScannerException(
249 "Scanner does not exist",
251 ScanError_InvalidContext
252 );
253
254 std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData];
255 if( pHolder->m_bBusy )
256 throw ScannerException(
257 "Scanner is busy",
259 ScanError_ScanInProgress
260 );
261
262 pHolder->m_bBusy = true;
263 SaneDlg aDlg(Application::GetFrameWeld(mxDialogParent), pHolder->m_aSane, listener.is());
264 bRet = aDlg.run();
265 bScan = aDlg.getDoScan();
266 pHolder->m_bBusy = false;
267 }
268 if ( bScan )
269 startScan( scanner_context, listener );
270
271 return bRet;
272}
273
274
275void ScannerManager::startScan( const ScannerContext& scanner_context,
277{
278 osl::MutexGuard aGuard( theSaneProtector::get() );
279 sanevec &rSanes = theSanes::get().m_aSanes;
280
281 SAL_INFO("extensions.scanner", "ScannerManager::startScan");
282
283 if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() )
284 throw ScannerException(
285 "Scanner does not exist",
287 ScanError_InvalidContext
288 );
289 std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData];
290 if( pHolder->m_bBusy )
291 throw ScannerException(
292 "Scanner is busy",
294 ScanError_ScanInProgress
295 );
296 pHolder->m_bBusy = true;
297
298 ScannerThread* pThread = new ScannerThread( pHolder, listener, this );
299 pThread->create();
300}
301
302
303ScanError ScannerManager::getError( const ScannerContext& scanner_context )
304{
305 osl::MutexGuard aGuard( theSaneProtector::get() );
306 sanevec &rSanes = theSanes::get().m_aSanes;
307
308 if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() )
309 throw ScannerException(
310 "Scanner does not exist",
312 ScanError_InvalidContext
313 );
314
315 std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData];
316
317 return pHolder->m_nError;
318}
319
320
321Reference< css::awt::XBitmap > ScannerManager::getBitmap( const ScannerContext& scanner_context )
322{
323 osl::MutexGuard aGuard( theSaneProtector::get() );
324 sanevec &rSanes = theSanes::get().m_aSanes;
325
326 if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() )
327 throw ScannerException(
328 "Scanner does not exist",
330 ScanError_InvalidContext
331 );
332 std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData];
333
334 osl::MutexGuard aProtGuard( pHolder->m_aProtector );
335
336 Reference< css::awt::XBitmap > xRet( pHolder->m_xBitmap );
337 pHolder->m_xBitmap.clear();
338
339 return xRet;
340}
341
342/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static weld::Window * GetFrameWeld(const css::uno::Reference< css::awt::XWindow > &rWindow)
virtual css::awt::Size SAL_CALL getSize() override
Definition: scanunx.cxx:43
virtual Sequence< sal_Int8 > SAL_CALL getDIB() override
Definition: scanunx.cxx:65
virtual ~BitmapTransporter() override
Definition: scanunx.cxx:37
osl::Mutex m_aProtector
Definition: sane.hxx:41
SvMemoryStream m_aStream
Definition: sane.hxx:40
bool getDoScan() const
Definition: sanedlg.hxx:108
virtual short run() override
Definition: sanedlg.cxx:305
Definition: sane.hxx:60
static bool IsSane()
Definition: sane.hxx:111
virtual Sequence< sal_Int8 > SAL_CALL getDIB() override
Definition: scanunx.cxx:208
virtual css::awt::Size SAL_CALL getSize() override
Definition: scanunx.cxx:200
virtual Sequence< ScannerContext > SAL_CALL getAvailableScanners() override
Definition: scanunx.cxx:214
static void AcquireData()
Definition: scanunx.cxx:186
virtual ScanError SAL_CALL getError(const ScannerContext &scanner_context) override
Definition: scanunx.cxx:303
css::uno::Reference< css::awt::XWindow > mxDialogParent
Definition: scanner.hxx:44
void ReleaseData()
Definition: scanunx.cxx:193
virtual void SAL_CALL startScan(const ScannerContext &scanner_context, const Reference< css::lang::XEventListener > &rxListener) override
Definition: scanunx.cxx:275
virtual Reference< css::awt::XBitmap > SAL_CALL getBitmap(const ScannerContext &scanner_context) override
Definition: scanunx.cxx:321
virtual sal_Bool SAL_CALL configureScannerAndScan(ScannerContext &scanner_context, const Reference< css::lang::XEventListener > &rxListener) override
Definition: scanunx.cxx:236
virtual sal_uInt64 TellEnd() override
sal_uInt64 Tell() const
sal_uInt64 Seek(sal_uInt64 nPos)
SvStream & ReadInt32(sal_Int32 &rInt32)
std::size_t ReadBytes(void *pData, std::size_t nSize)
Reference< XTextListener > m_xListener
#define SAL_INFO(area, stream)
def run(arg=None, arg2=-1)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
ToolBarManager * m_pManager
unsigned char sal_Bool