| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_fpicker.hxx" |
| |
| //------------------------------------------------------------------------ |
| // includes |
| //------------------------------------------------------------------------ |
| #include <osl/diagnose.h> |
| #include "asynceventnotifier.hxx" |
| #include <com/sun/star/uno/RuntimeException.hpp> |
| #include <com/sun/star/ui/dialogs/XFilePickerListener.hpp> |
| |
| #include <process.h> |
| #include <memory> |
| #include "SolarMutex.hxx" |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| using namespace com::sun::star; |
| using ::com::sun::star::ui::dialogs::XFilePickerListener; |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| CAsyncEventNotifier::CAsyncEventNotifier(cppu::OBroadcastHelper& rBroadcastHelper) : |
| m_hThread(0), |
| m_bRun(false), |
| m_ThreadId(0), |
| m_rBroadcastHelper(rBroadcastHelper), |
| m_NotifyEvent(m_hEvents[0]), |
| m_ResumeNotifying(m_hEvents[1]) |
| { |
| // m_NotifyEvent |
| m_hEvents[0] = CreateEvent(0, /* no security */ |
| true, /* manual reset */ |
| false, /* initial state not signaled */ |
| 0); /* automatic name */ |
| |
| // m_ResumeNotifying |
| m_hEvents[1] = CreateEvent(0, /* no security */ |
| true, /* manual reset */ |
| false, /* initial state not signaled */ |
| 0); /* automatic name */ |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| CAsyncEventNotifier::~CAsyncEventNotifier() |
| { |
| OSL_ENSURE(0 == m_hThread,"Thread not stopped, destroying this instance leads to desaster"); |
| |
| CloseHandle(m_hEvents[0]); |
| CloseHandle(m_hEvents[1]); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void SAL_CALL CAsyncEventNotifier::addListener(const uno::Type& aType , |
| const uno::Reference< uno::XInterface >& xListener) |
| { |
| if ( m_rBroadcastHelper.bDisposed ) |
| throw lang::DisposedException( |
| ::rtl::OUString::createFromAscii( "FilePicker is already disposed" ), |
| uno::Reference< uno::XInterface >() ); |
| |
| if ( m_rBroadcastHelper.bInDispose ) |
| throw lang::DisposedException( |
| ::rtl::OUString::createFromAscii( "FilePicker will be disposed now." ), |
| uno::Reference< uno::XInterface >() ); |
| |
| m_rBroadcastHelper.aLC.addInterface( aType, xListener ); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void SAL_CALL CAsyncEventNotifier::removeListener(const uno::Type& aType , |
| const uno::Reference< uno::XInterface >& xListener) |
| { |
| if ( m_rBroadcastHelper.bDisposed ) |
| throw lang::DisposedException( |
| ::rtl::OUString::createFromAscii( "FilePicker is already disposed." ), |
| uno::Reference< uno::XInterface >() ); |
| |
| m_rBroadcastHelper.aLC.removeInterface( aType, xListener ); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| bool SAL_CALL CAsyncEventNotifier::startup(bool bCreateSuspended) |
| { |
| osl::MutexGuard aGuard(m_Mutex); |
| |
| // m_bRun may already be false because of a |
| // call to stop but the thread did not yet |
| // terminate so m_hEventNotifierThread is |
| // yet a valid thread handle that should |
| // not be overwritten |
| if (!m_bRun) |
| { |
| if (!bCreateSuspended) |
| SetEvent(m_ResumeNotifying); |
| |
| m_hThread = (HANDLE)_beginthreadex( |
| NULL, 0, CAsyncEventNotifier::ThreadProc, this, 0, &m_ThreadId); |
| |
| OSL_ASSERT(0 != m_hThread); |
| |
| if (m_hThread) |
| m_bRun = true; |
| } |
| |
| OSL_POSTCOND(m_bRun,"Could not start event notifier!"); |
| |
| return m_bRun; |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void SAL_CALL CAsyncEventNotifier::shutdown() |
| { |
| unsigned nThreadId = GetCurrentThreadId(); |
| |
| OSL_PRECOND(nThreadId != m_ThreadId, "Method called in wrong thread context!"); |
| |
| osl::ResettableMutexGuard aGuard(m_Mutex); |
| |
| OSL_PRECOND(m_bRun,"Event notifier does not run!"); |
| |
| m_bRun = false; |
| m_EventList.clear(); |
| |
| // awake the the notifier thread |
| SetEvent(m_ResumeNotifying); |
| SetEvent(m_NotifyEvent); |
| |
| // releas the mutex here because the event |
| // notifier thread may need it to finish |
| aGuard.clear(); |
| |
| // we are waiting infinite, so error will |
| // be better detected in form of deadlocks |
| if (WaitForSingleObject(m_hThread, INFINITE) == WAIT_FAILED) { |
| OSL_ENSURE(false, "Waiting for thread termination failed!"); |
| } |
| |
| // lock mutex again to reset m_hThread |
| // and prevent a race with start() |
| aGuard.reset(); |
| |
| CloseHandle(m_hThread); |
| m_hThread = 0; |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void CAsyncEventNotifier::suspend() |
| { |
| ResetEvent(m_ResumeNotifying); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void CAsyncEventNotifier::resume() |
| { |
| SetEvent(m_ResumeNotifying); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void SAL_CALL CAsyncEventNotifier::notifyEvent(CEventNotification* EventNotification) |
| { |
| osl::MutexGuard aGuard(m_Mutex); |
| |
| OSL_ENSURE(m_bRun,"Event notifier is not running!"); |
| |
| if (m_bRun) |
| { |
| m_EventList.push_back(EventNotification); |
| SetEvent(m_NotifyEvent); |
| } |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| size_t SAL_CALL CAsyncEventNotifier::getEventListSize() |
| { |
| osl::MutexGuard aGuard(m_Mutex); |
| return m_EventList.size(); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void SAL_CALL CAsyncEventNotifier::resetNotifyEvent() |
| { |
| osl::MutexGuard aGuard(m_Mutex); |
| if (0 == m_EventList.size()) |
| ResetEvent(m_NotifyEvent); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| CEventNotification* SAL_CALL CAsyncEventNotifier::getNextEventRecord() |
| { |
| osl::MutexGuard aGuard(m_Mutex); |
| return m_EventList.front(); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void SAL_CALL CAsyncEventNotifier::removeNextEventRecord() |
| { |
| osl::MutexGuard aGuard(m_Mutex); |
| m_EventList.pop_front(); |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| void SAL_CALL CAsyncEventNotifier::run() |
| { |
| while (m_bRun) |
| { |
| WaitForMultipleObjects(2, m_hEvents, true, INFINITE); |
| |
| if (m_bRun) |
| { |
| while (getEventListSize() > 0) |
| { |
| std::auto_ptr<CEventNotification> EventNotification(getNextEventRecord()); |
| removeNextEventRecord(); |
| |
| ::cppu::OInterfaceContainerHelper* pICHelper = |
| m_rBroadcastHelper.getContainer(getCppuType((uno::Reference<XFilePickerListener>*)0)); |
| |
| if (pICHelper) |
| { |
| ::cppu::OInterfaceIteratorHelper iter(*pICHelper); |
| |
| while(iter.hasMoreElements()) |
| { |
| try |
| { |
| EventNotification->notifyEventListener(iter.next()); |
| } |
| catch(uno::RuntimeException&) |
| { |
| OSL_ENSURE(sal_False,"RuntimeException during event dispatching"); |
| } |
| } |
| } |
| |
| } // while(getEventListSize() > 0) |
| |
| resetNotifyEvent(); |
| |
| } // if (m_bRun) |
| |
| } // while(m_bRun) |
| } |
| |
| //------------------------------------------------ |
| // |
| //------------------------------------------------ |
| |
| unsigned int WINAPI CAsyncEventNotifier::ThreadProc(LPVOID pParam) |
| { |
| CAsyncEventNotifier* pInst = reinterpret_cast< CAsyncEventNotifier* >(pParam); |
| OSL_ASSERT(pInst); |
| |
| pInst->run(); |
| |
| return 0; |
| } |