Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 113, column 13
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name event.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/source/window/event.cxx

/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx

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 <vcl/event.hxx>
21#include <vcl/window.hxx>
22#include <vcl/dockwin.hxx>
23#include <vcl/layout.hxx>
24#include <vcl/opengl/OpenGLWrapper.hxx>
25#include <sal/log.hxx>
26
27#include <window.h>
28#include <svdata.hxx>
29#include <salframe.hxx>
30#include <config_features.h>
31#include <comphelper/scopeguard.hxx>
32
33namespace vcl {
34
35void Window::DataChanged( const DataChangedEvent& )
36{
37}
38
39void Window::NotifyAllChildren( DataChangedEvent& rDCEvt )
40{
41 CompatDataChanged( rDCEvt );
42
43 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
44 while ( pChild )
45 {
46 pChild->NotifyAllChildren( rDCEvt );
47 pChild = pChild->mpWindowImpl->mpNext;
48 }
49}
50
51bool Window::PreNotify( NotifyEvent& rNEvt )
52{
53 bool bDone = false;
54 if ( mpWindowImpl->mpParent && !ImplIsOverlapWindow() )
55 bDone = mpWindowImpl->mpParent->CompatPreNotify( rNEvt );
56
57 if ( !bDone )
58 {
59 if( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
60 {
61 bool bCompoundFocusChanged = false;
62 if ( mpWindowImpl->mbCompoundControl && !mpWindowImpl->mbCompoundControlHasFocus && HasChildPathFocus() )
63 {
64 mpWindowImpl->mbCompoundControlHasFocus = true;
65 bCompoundFocusChanged = true;
66 }
67
68 if ( bCompoundFocusChanged || ( rNEvt.GetWindow() == this ) )
69 CallEventListeners( VclEventId::WindowGetFocus );
70 }
71 else if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
72 {
73 bool bCompoundFocusChanged = false;
74 if ( mpWindowImpl->mbCompoundControl && mpWindowImpl->mbCompoundControlHasFocus && !HasChildPathFocus() )
75 {
76 mpWindowImpl->mbCompoundControlHasFocus = false ;
77 bCompoundFocusChanged = true;
78 }
79
80 if ( bCompoundFocusChanged || ( rNEvt.GetWindow() == this ) )
81 CallEventListeners( VclEventId::WindowLoseFocus );
82 }
83
84 // #82968# mouse and key events will be notified after processing ( in ImplNotifyKeyMouseCommandEventListeners() )!
85 // see also ImplHandleMouseEvent(), ImplHandleKey()
86
87 }
88
89 return bDone;
90}
91
92namespace
93{
94 bool parentNotDialogControl(Window* pWindow)
95 {
96 vcl::Window* pParent = getNonLayoutParent(pWindow);
97 if (!pParent)
98 return true;
99 return ((pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL);
100 }
101}
102
103bool Window::EventNotify( NotifyEvent& rNEvt )
104{
105 bool bRet = false;
106
107 if (IsDisposed())
108 return false;
109
110 // check for docking window
111 // but do nothing if window is docked and locked
112 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
113 if (pWrapper && ( pWrapper->IsFloatingMode() || !pWrapper->IsLocked() ))
114 {
115 const bool bDockingSupportCrippled = !StyleSettings::GetDockingFloatsSupported();
116
117 if ( rNEvt.GetType() == MouseNotifyEvent::MOUSEBUTTONDOWN )
118 {
119 const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
120 bool bHit = pWrapper->GetDragArea().IsInside( pMEvt->GetPosPixel() );
121 if ( pMEvt->IsLeft() )
122 {
123 if (!bDockingSupportCrippled && pMEvt->IsMod1() && (pMEvt->GetClicks() == 2))
124 {
125 // ctrl double click toggles floating mode
126 pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() );
127 return true;
128 }
129 else if ( pMEvt->GetClicks() == 1 && bHit)
130 {
131 // allow start docking during mouse move
132 pWrapper->ImplEnableStartDocking();
133 return true;
134 }
135 }
136 }
137 else if ( rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE )
138 {
139 const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
140 bool bHit = pWrapper->GetDragArea().IsInside( pMEvt->GetPosPixel() );
141 if ( pMEvt->IsLeft() )
142 {
143 // check if a single click initiated this sequence ( ImplStartDockingEnabled() )
144 // check if window is docked and
145 if( pWrapper->ImplStartDockingEnabled() && !pWrapper->IsFloatingMode() &&
146 !pWrapper->IsDocking() && bHit )
147 {
148 Point aPos = pMEvt->GetPosPixel();
149 vcl::Window* pWindow = rNEvt.GetWindow();
150 if ( pWindow != this )
151 {
152 aPos = pWindow->OutputToScreenPixel( aPos );
153 aPos = ScreenToOutputPixel( aPos );
154 }
155 pWrapper->ImplStartDocking( aPos );
156 }
157 return true;
158 }
159 }
160 else if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
161 {
162 const vcl::KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode();
163 if (rKey.GetCode() == KEY_F10 && rKey.GetModifier() &&
164 rKey.IsShift() && rKey.IsMod1() && !bDockingSupportCrippled)
165 {
166 pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() );
167 /* At this point the floating toolbar frame does not have the
168 * input focus since these frames don't get the focus per default
169 * To enable keyboard handling of this toolbar set the input focus
170 * to the frame. This needs to be done with ToTop since GrabFocus
171 * would not notice any change since "this" already has the focus.
172 */
173 if( pWrapper->IsFloatingMode() )
174 ToTop( ToTopFlags::GrabFocusOnly );
175 return true;
176 }
177 }
178 }
179
180 // manage the dialogs
181 if ( (GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL )
182 {
183 // if the parent also has dialog control activated, the parent takes over control
184 if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) || (rNEvt.GetType() == MouseNotifyEvent::KEYUP) )
185 {
186 // ScGridWindow has WB_DIALOGCONTROL set, so pressing tab in ScCheckListMenuControl won't
187 // get processed here by the toplevel DockingWindow of ScCheckListMenuControl by
188 // just checking if parentNotDialogControl is true
189 bool bTopLevelFloatingWindow = (pWrapper && pWrapper->IsFloatingMode());
190 if (ImplIsOverlapWindow() || parentNotDialogControl(this) || bTopLevelFloatingWindow)
191 {
192 bRet = ImplDlgCtrl( *rNEvt.GetKeyEvent(), rNEvt.GetType() == MouseNotifyEvent::KEYINPUT );
193 }
194 }
195 else if ( (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) || (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS) )
196 {
197 ImplDlgCtrlFocusChanged( rNEvt.GetWindow(), rNEvt.GetType() == MouseNotifyEvent::GETFOCUS );
198 if ( (rNEvt.GetWindow() == this) && (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) &&
199 !(GetStyle() & WB_TABSTOP) && !(mpWindowImpl->mnDlgCtrlFlags & DialogControlFlags::WantFocus) )
200 {
201 vcl::Window* pFirstChild = ImplGetDlgWindow( 0, GetDlgWindowType::First );
202 if ( pFirstChild )
203 pFirstChild->ImplControlFocus();
204 }
205 }
206 }
207
208 if ( !bRet )
209 {
210 if ( mpWindowImpl->mpParent && !ImplIsOverlapWindow() )
211 bRet = mpWindowImpl->mpParent->CompatNotify( rNEvt );
212 }
213
214 return bRet;
215}
216
217void Window::CallEventListeners( VclEventId nEvent, void* pData )
218{
219 VclWindowEvent aEvent( this, nEvent, pData );
220
221 VclPtr<vcl::Window> xWindow = this;
222
223 Application::ImplCallEventListeners( aEvent );
224
225 if ( xWindow->IsDisposed() )
4
Assuming the condition is false
5
Taking false branch
226 return;
227
228 // If maEventListeners is empty, the XVCLWindow has not yet been initialized.
229 // Calling GetComponentInterface will do that.
230 if (mpWindowImpl->maEventListeners.empty() && pData)
6
Assuming the condition is false
231 xWindow->GetComponentInterface();
232
233 if (!mpWindowImpl->maEventListeners.empty())
7
Assuming the condition is false
8
Taking false branch
234 {
235 // Copy the list, because this can be destroyed when calling a Link...
236 std::vector<Link<VclWindowEvent&,void>> aCopy( mpWindowImpl->maEventListeners );
237 // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour
238 mpWindowImpl->mnEventListenersIteratingCount++;
239 auto& rWindowImpl = *mpWindowImpl;
240 comphelper::ScopeGuard aGuard(
241 [&rWindowImpl, &xWindow]()
242 {
243 if (!xWindow->IsDisposed())
244 {
245 rWindowImpl.mnEventListenersIteratingCount--;
246 if (rWindowImpl.mnEventListenersIteratingCount == 0)
247 rWindowImpl.maEventListenersDeleted.clear();
248 }
249 }
250 );
251 for ( const Link<VclWindowEvent&,void>& rLink : aCopy )
252 {
253 if (xWindow->IsDisposed()) break;
254 // check this hasn't been removed in some re-enterancy scenario fdo#47368
255 if( rWindowImpl.maEventListenersDeleted.find(rLink) == rWindowImpl.maEventListenersDeleted.end() )
256 rLink.Call( aEvent );
257 }
258 }
259
260 while ( xWindow )
9
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
38
Loop condition is true. Entering loop body
261 {
262
263 if ( xWindow->IsDisposed() )
10
Assuming the condition is false
11
Taking false branch
17
Assuming the condition is false
18
Taking false branch
39
Assuming the condition is false
40
Taking false branch
264 return;
265
266 auto& rWindowImpl = *xWindow->mpWindowImpl;
267 if (!rWindowImpl.maChildEventListeners.empty())
12
Assuming the condition is false
13
Taking false branch
19
Assuming the condition is true
20
Taking true branch
41
Assuming the condition is true
42
Taking true branch
268 {
269 // Copy the list, because this can be destroyed when calling a Link...
270 std::vector<Link<VclWindowEvent&,void>> aCopy( rWindowImpl.maChildEventListeners );
271 // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour
272 rWindowImpl.mnChildEventListenersIteratingCount++;
273 comphelper::ScopeGuard aGuard(
274 [&rWindowImpl, &xWindow]()
275 {
276 if (!xWindow->IsDisposed())
277 {
278 rWindowImpl.mnChildEventListenersIteratingCount--;
279 if (rWindowImpl.mnChildEventListenersIteratingCount == 0)
280 rWindowImpl.maChildEventListenersDeleted.clear();
281 }
282 }
283 );
284 for ( const Link<VclWindowEvent&,void>& rLink : aCopy )
285 {
286 if (xWindow->IsDisposed())
21
Assuming the condition is false
22
Taking false branch
43
Assuming the condition is true
44
Taking true branch
287 return;
45
Calling implicit destructor for 'VclPtr<vcl::Window>'
46
Calling '~Reference'
288 // Check this hasn't been removed in some re-enterancy scenario fdo#47368.
289 if( rWindowImpl.maChildEventListenersDeleted.find(rLink) == rWindowImpl.maChildEventListenersDeleted.end() )
23
Taking false branch
290 rLink.Call( aEvent );
291 }
292 }
293
294 if ( xWindow->IsDisposed() )
14
Assuming the condition is false
15
Taking false branch
24
Assuming the condition is false
25
Taking false branch
295 return;
296
297 xWindow = xWindow->GetParent();
26
Calling 'VclPtr::operator='
37
Returning; memory was released
298 }
299}
300
301void Window::AddEventListener( const Link<VclWindowEvent&,void>& rEventListener )
302{
303 mpWindowImpl->maEventListeners.push_back( rEventListener );
304}
305
306void Window::RemoveEventListener( const Link<VclWindowEvent&,void>& rEventListener )
307{
308 if (mpWindowImpl)
309 {
310 auto& rListeners = mpWindowImpl->maEventListeners;
311 rListeners.erase( std::remove(rListeners.begin(), rListeners.end(), rEventListener ), rListeners.end() );
312 if (mpWindowImpl->mnEventListenersIteratingCount)
313 mpWindowImpl->maEventListenersDeleted.insert(rEventListener);
314 }
315}
316
317void Window::AddChildEventListener( const Link<VclWindowEvent&,void>& rEventListener )
318{
319 mpWindowImpl->maChildEventListeners.push_back( rEventListener );
320}
321
322void Window::RemoveChildEventListener( const Link<VclWindowEvent&,void>& rEventListener )
323{
324 if (mpWindowImpl)
325 {
326 auto& rListeners = mpWindowImpl->maChildEventListeners;
327 rListeners.erase( std::remove(rListeners.begin(), rListeners.end(), rEventListener ), rListeners.end() );
328 if (mpWindowImpl->mnChildEventListenersIteratingCount)
329 mpWindowImpl->maChildEventListenersDeleted.insert(rEventListener);
330 }
331}
332
333ImplSVEvent * Window::PostUserEvent( const Link<void*,void>& rLink, void* pCaller, bool bReferenceLink )
334{
335 std::unique_ptr<ImplSVEvent> pSVEvent(new ImplSVEvent);
336 pSVEvent->mpData = pCaller;
337 pSVEvent->maLink = rLink;
338 pSVEvent->mpWindow = this;
339 pSVEvent->mbCall = true;
340 if (bReferenceLink)
341 {
342 // Double check that this is indeed a vcl::Window instance.
343 assert(dynamic_cast<vcl::Window *>((static_cast <bool> (dynamic_cast<vcl::Window *>(
static_cast<OutputDevice *>(rLink.GetInstance())) == static_cast
<vcl::Window *>(rLink.GetInstance())) ? void (0) : __assert_fail
("dynamic_cast<vcl::Window *>( static_cast<OutputDevice *>(rLink.GetInstance())) == static_cast<vcl::Window *>(rLink.GetInstance())"
, "/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
, 345, __extension__ __PRETTY_FUNCTION__))
344 static_cast<OutputDevice *>(rLink.GetInstance())) ==(static_cast <bool> (dynamic_cast<vcl::Window *>(
static_cast<OutputDevice *>(rLink.GetInstance())) == static_cast
<vcl::Window *>(rLink.GetInstance())) ? void (0) : __assert_fail
("dynamic_cast<vcl::Window *>( static_cast<OutputDevice *>(rLink.GetInstance())) == static_cast<vcl::Window *>(rLink.GetInstance())"
, "/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
, 345, __extension__ __PRETTY_FUNCTION__))
345 static_cast<vcl::Window *>(rLink.GetInstance()))(static_cast <bool> (dynamic_cast<vcl::Window *>(
static_cast<OutputDevice *>(rLink.GetInstance())) == static_cast
<vcl::Window *>(rLink.GetInstance())) ? void (0) : __assert_fail
("dynamic_cast<vcl::Window *>( static_cast<OutputDevice *>(rLink.GetInstance())) == static_cast<vcl::Window *>(rLink.GetInstance())"
, "/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
, 345, __extension__ __PRETTY_FUNCTION__))
;
346 pSVEvent->mpInstanceRef = static_cast<vcl::Window *>(rLink.GetInstance());
347 }
348
349 auto pTmpEvent = pSVEvent.get();
350 if (!mpWindowImpl->mpFrame->PostEvent( std::move(pSVEvent) ))
351 return nullptr;
352 return pTmpEvent;
353}
354
355void Window::RemoveUserEvent( ImplSVEvent * nUserEvent )
356{
357 SAL_WARN_IF( nUserEvent->mpWindow.get() != this, "vcl",do { if (true && (nUserEvent->mpWindow.get() != this
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
358 "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed" )do { if (true && (nUserEvent->mpWindow.get() != this
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "358" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
359 SAL_WARN_IF( !nUserEvent->mbCall, "vcl",do { if (true && (!nUserEvent->mbCall)) { switch (
sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
360 "Window::RemoveUserEvent(): Event is already removed" )do { if (true && (!nUserEvent->mbCall)) { switch (
sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Window::RemoveUserEvent(): Event is already removed"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Window::RemoveUserEvent(): Event is already removed"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Window::RemoveUserEvent(): Event is already removed"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/event.cxx"
":" "360" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
361
362 if ( nUserEvent->mpWindow )
363 {
364 nUserEvent->mpWindow = nullptr;
365 }
366
367 nUserEvent->mbCall = false;
368}
369
370
371static MouseEvent ImplTranslateMouseEvent( const MouseEvent& rE, vcl::Window const * pSource, vcl::Window const * pDest )
372{
373 // the mouse event occurred in a different window, we need to translate the coordinates of
374 // the mouse cursor within that (source) window to the coordinates the mouse cursor would
375 // be in the destination window
376 Point aPos = pSource->OutputToScreenPixel( rE.GetPosPixel() );
377 return MouseEvent( pDest->ScreenToOutputPixel( aPos ), rE.GetClicks(), rE.GetMode(), rE.GetButtons(), rE.GetModifier() );
378}
379
380void Window::ImplNotifyKeyMouseCommandEventListeners( NotifyEvent& rNEvt )
381{
382 if( rNEvt.GetType() == MouseNotifyEvent::COMMAND )
383 {
384 const CommandEvent* pCEvt = rNEvt.GetCommandEvent();
385 if ( pCEvt->GetCommand() != CommandEventId::ContextMenu )
386 // non context menu events are not to be notified up the chain
387 // so we return immediately
388 return;
389
390 if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
391 {
392 // not interested: The event listeners are already called in ::Command,
393 // and calling them here a second time doesn't make sense
394 if ( rNEvt.GetWindow() != this )
395 {
396 CommandEvent aCommandEvent;
397
398 if ( !pCEvt->IsMouseEvent() )
399 {
400 aCommandEvent = *pCEvt;
401 }
402 else
403 {
404 // the mouse event occurred in a different window, we need to translate the coordinates of
405 // the mouse cursor within that window to the coordinates the mouse cursor would be in the
406 // current window
407 vcl::Window* pSource = rNEvt.GetWindow();
408 Point aPos = pSource->OutputToScreenPixel( pCEvt->GetMousePosPixel() );
409 aCommandEvent = CommandEvent( ScreenToOutputPixel( aPos ), pCEvt->GetCommand(), pCEvt->IsMouseEvent(), pCEvt->GetEventData() );
410 }
411
412 CallEventListeners( VclEventId::WindowCommand, &aCommandEvent );
413 }
414 }
415 }
416
417 // #82968# notify event listeners for mouse and key events separately and
418 // not in PreNotify ( as for focus listeners )
419 // this allows for processing those events internally first and pass it to
420 // the toolkit later
421
422 VclPtr<vcl::Window> xWindow = this;
423
424 if( rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE )
425 {
426 if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
427 {
428 if ( rNEvt.GetWindow() == this )
429 CallEventListeners( VclEventId::WindowMouseMove, const_cast<MouseEvent *>(rNEvt.GetMouseEvent()) );
430 else
431 {
432 MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
433 CallEventListeners( VclEventId::WindowMouseMove, &aMouseEvent );
434 }
435 }
436 }
437 else if( rNEvt.GetType() == MouseNotifyEvent::MOUSEBUTTONUP )
438 {
439 if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
440 {
441 if ( rNEvt.GetWindow() == this )
442 CallEventListeners( VclEventId::WindowMouseButtonUp, const_cast<MouseEvent *>(rNEvt.GetMouseEvent()) );
443 else
444 {
445 MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
446 CallEventListeners( VclEventId::WindowMouseButtonUp, &aMouseEvent );
447 }
448 }
449 }
450 else if( rNEvt.GetType() == MouseNotifyEvent::MOUSEBUTTONDOWN )
451 {
452 if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
453 {
454 if ( rNEvt.GetWindow() == this )
455 CallEventListeners( VclEventId::WindowMouseButtonDown, const_cast<MouseEvent *>(rNEvt.GetMouseEvent()) );
456 else
457 {
458 MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
459 CallEventListeners( VclEventId::WindowMouseButtonDown, &aMouseEvent );
460 }
461 }
462 }
463 else if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
464 {
465 if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
466 CallEventListeners( VclEventId::WindowKeyInput, const_cast<KeyEvent *>(rNEvt.GetKeyEvent()) );
467 }
468 else if( rNEvt.GetType() == MouseNotifyEvent::KEYUP )
469 {
470 if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
471 CallEventListeners( VclEventId::WindowKeyUp, const_cast<KeyEvent *>(rNEvt.GetKeyEvent()) );
472 }
473
474 if ( xWindow->IsDisposed() )
475 return;
476
477 // #106721# check if we're part of a compound control and notify
478 vcl::Window *pParent = ImplGetParent();
479 while( pParent )
480 {
481 if( pParent->IsCompoundControl() )
482 {
483 pParent->ImplNotifyKeyMouseCommandEventListeners( rNEvt );
484 break;
485 }
486 pParent = pParent->ImplGetParent();
487 }
488}
489
490void Window::ImplCallInitShow()
491{
492 mpWindowImpl->mbReallyShown = true;
493 mpWindowImpl->mbInInitShow = true;
494 CompatStateChanged( StateChangedType::InitShow );
495 mpWindowImpl->mbInInitShow = false;
496
497 vcl::Window* pWindow = mpWindowImpl->mpFirstOverlap;
498 while ( pWindow )
499 {
500 if ( pWindow->mpWindowImpl->mbVisible )
501 pWindow->ImplCallInitShow();
502 pWindow = pWindow->mpWindowImpl->mpNext;
503 }
504
505 pWindow = mpWindowImpl->mpFirstChild;
506 while ( pWindow )
507 {
508 if ( pWindow->mpWindowImpl->mbVisible )
509 pWindow->ImplCallInitShow();
510 pWindow = pWindow->mpWindowImpl->mpNext;
511 }
512}
513
514
515void Window::ImplCallResize()
516{
517 mpWindowImpl->mbCallResize = false;
518
519 // OpenGL has a charming feature of black clearing the whole window
520 // some legacy code eg. the app-menu has the beautiful feature of
521 // avoiding re-paints when width doesn't change => invalidate all.
522#if HAVE_FEATURE_OPENGL1
523 if( OpenGLWrapper::isVCLOpenGLEnabled() )
524 Invalidate();
525
526 // Normally we avoid blanking on re-size unless people might notice:
527 else
528#endif
529 if( GetBackground().IsGradient() )
530 Invalidate();
531
532 Resize();
533
534 // #88419# Most classes don't call the base class in Resize() and Move(),
535 // => Call ImpleResize/Move instead of Resize/Move directly...
536 CallEventListeners( VclEventId::WindowResize );
537}
538
539void Window::ImplCallMove()
540{
541 mpWindowImpl->mbCallMove = false;
542
543 if( mpWindowImpl->mbFrame )
1
Assuming field 'mbFrame' is false
2
Taking false branch
544 {
545 // update frame position
546 SalFrame *pParentFrame = nullptr;
547 vcl::Window *pParent = ImplGetParent();
548 while( pParent )
549 {
550 if( pParent->mpWindowImpl->mpFrame != mpWindowImpl->mpFrame )
551 {
552 pParentFrame = pParent->mpWindowImpl->mpFrame;
553 break;
554 }
555 pParent = pParent->GetParent();
556 }
557
558 SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
559 mpWindowImpl->maPos = Point( g.nX, g.nY );
560 if( pParentFrame )
561 {
562 g = pParentFrame->GetGeometry();
563 mpWindowImpl->maPos -= Point( g.nX, g.nY );
564 }
565 // the client window and all its subclients have the same position as the borderframe
566 // this is important for floating toolbars where the borderwindow is a floating window
567 // which has another borderwindow (ie the system floating window)
568 vcl::Window *pClientWin = mpWindowImpl->mpClientWindow;
569 while( pClientWin )
570 {
571 pClientWin->mpWindowImpl->maPos = mpWindowImpl->maPos;
572 pClientWin = pClientWin->mpWindowImpl->mpClientWindow;
573 }
574 }
575
576 Move();
577
578 CallEventListeners( VclEventId::WindowMove );
3
Calling 'Window::CallEventListeners'
579}
580
581void Window::ImplCallFocusChangeActivate( vcl::Window* pNewOverlapWindow,
582 vcl::Window* pOldOverlapWindow )
583{
584 ImplSVData* pSVData = ImplGetSVData();
585 vcl::Window* pNewRealWindow;
586 vcl::Window* pOldRealWindow;
587 bool bCallActivate = true;
588 bool bCallDeactivate = true;
589
590 if (!pOldOverlapWindow)
591 {
592 return;
593 }
594
595 pOldRealWindow = pOldOverlapWindow->ImplGetWindow();
596 if (!pNewOverlapWindow)
597 {
598 return;
599 }
600
601 pNewRealWindow = pNewOverlapWindow->ImplGetWindow();
602 if ( (pOldRealWindow->GetType() != WindowType::FLOATINGWINDOW) ||
603 pOldRealWindow->GetActivateMode() != ActivateModeFlags::NONE )
604 {
605 if ( (pNewRealWindow->GetType() == WindowType::FLOATINGWINDOW) &&
606 pNewRealWindow->GetActivateMode() == ActivateModeFlags::NONE)
607 {
608 pSVData->mpWinData->mpLastDeacWin = pOldOverlapWindow;
609 bCallDeactivate = false;
610 }
611 }
612 else if ( (pNewRealWindow->GetType() != WindowType::FLOATINGWINDOW) ||
613 pNewRealWindow->GetActivateMode() != ActivateModeFlags::NONE )
614 {
615 if (pSVData->mpWinData->mpLastDeacWin)
616 {
617 if (pSVData->mpWinData->mpLastDeacWin.get() == pNewOverlapWindow)
618 bCallActivate = false;
619 else
620 {
621 vcl::Window* pLastRealWindow = pSVData->mpWinData->mpLastDeacWin->ImplGetWindow();
622 pSVData->mpWinData->mpLastDeacWin->mpWindowImpl->mbActive = false;
623 pSVData->mpWinData->mpLastDeacWin->Deactivate();
624 if (pLastRealWindow != pSVData->mpWinData->mpLastDeacWin.get())
625 {
626 pLastRealWindow->mpWindowImpl->mbActive = true;
627 pLastRealWindow->Activate();
628 }
629 }
630 pSVData->mpWinData->mpLastDeacWin = nullptr;
631 }
632 }
633
634 if ( bCallDeactivate )
635 {
636 if( pOldOverlapWindow->mpWindowImpl->mbActive )
637 {
638 pOldOverlapWindow->mpWindowImpl->mbActive = false;
639 pOldOverlapWindow->Deactivate();
640 }
641 if ( pOldRealWindow != pOldOverlapWindow )
642 {
643 if( pOldRealWindow->mpWindowImpl->mbActive )
644 {
645 pOldRealWindow->mpWindowImpl->mbActive = false;
646 pOldRealWindow->Deactivate();
647 }
648 }
649 }
650 if ( !bCallActivate || pNewOverlapWindow->mpWindowImpl->mbActive )
651 return;
652
653 pNewOverlapWindow->mpWindowImpl->mbActive = true;
654 pNewOverlapWindow->Activate();
655
656 if ( pNewRealWindow != pNewOverlapWindow )
657 {
658 if( ! pNewRealWindow->mpWindowImpl->mbActive )
659 {
660 pNewRealWindow->mpWindowImpl->mbActive = true;
661 pNewRealWindow->Activate();
662 }
663 }
664}
665
666} /* namespace vcl */
667
668
669NotifyEvent::NotifyEvent( MouseNotifyEvent nEventType, vcl::Window* pWindow,
670 const void* pEvent )
671{
672 mpWindow = pWindow;
673 mpData = const_cast<void*>(pEvent);
674 mnEventType = nEventType;
675}
676
677/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
27
Calling 'Reference::set'
36
Returning; memory was released
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody
46.1
Field 'm_pBody' is non-null
46.1
Field 'm_pBody' is non-null
46.1
Field 'm_pBody' is non-null
46.1
Field 'm_pBody' is non-null
)
47
Taking true branch
113 m_pBody->release();
48
Use of memory after it is freed
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
28
Assuming 'pBody' is non-null
29
Taking true branch
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld
29.1
'pOld' is non-null
29.1
'pOld' is non-null
29.1
'pOld' is non-null
29.1
'pOld' is non-null
)
30
Taking true branch
127 pOld->release();
31
Calling 'VclReferenceBase::release'
35
Returning; memory was released
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
32
Assuming the condition is true
33
Taking true branch
40 delete this;
34
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif