Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/app/salusereventlist.cxx
Line
Count
Source
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 <salusereventlist.hxx>
21
#include <salwtype.hxx>
22
23
#include <algorithm>
24
#include <cstdlib>
25
#include <exception>
26
#include <typeinfo>
27
28
#include <com/sun/star/uno/Exception.hpp>
29
#include <tools/debug.hxx>
30
#include <comphelper/diagnose_ex.hxx>
31
#include <sal/log.hxx>
32
#include <sal/types.h>
33
#include <svdata.hxx>
34
35
SalUserEventList::SalUserEventList()
36
106
    : m_bAllUserEventProcessedSignaled( true )
37
106
    , m_aProcessingThread(0)
38
106
{
39
106
}
40
41
SalUserEventList::~SalUserEventList()
42
0
{
43
0
}
44
45
void SalUserEventList::insertFrame( SalFrame* pFrame )
46
8.20k
{
47
8.20k
    auto aPair = m_aFrames.insert( pFrame );
48
8.20k
    assert( aPair.second ); (void) aPair;
49
8.20k
}
50
51
void SalUserEventList::eraseFrame( SalFrame* pFrame )
52
4.08k
{
53
4.08k
    auto it = m_aFrames.find( pFrame );
54
4.08k
    assert( it != m_aFrames.end() );
55
4.08k
    if ( it != m_aFrames.end() )
56
4.08k
        m_aFrames.erase( it );
57
4.08k
}
58
59
bool SalUserEventList::DispatchUserEvents( bool bHandleAllCurrentEvents )
60
55.0k
{
61
55.0k
    bool bWasEvent = false;
62
55.0k
    oslThreadIdentifier aCurId = osl::Thread::getCurrentIdentifier();
63
64
55.0k
    DBG_TESTSOLARMUTEX();
65
55.0k
    std::unique_lock aResettableListGuard(m_aUserEventsMutex);
66
67
55.0k
    if (!m_aUserEvents.empty())
68
3.92k
    {
69
3.92k
        if (bHandleAllCurrentEvents)
70
0
        {
71
0
            if (m_aProcessingUserEvents.empty())
72
0
                m_aProcessingUserEvents.swap(m_aUserEvents);
73
0
            else
74
0
                m_aProcessingUserEvents.splice(m_aProcessingUserEvents.end(), m_aUserEvents);
75
0
        }
76
3.92k
        else if (m_aProcessingUserEvents.empty())
77
3.92k
        {
78
3.92k
            m_aProcessingUserEvents.push_back( m_aUserEvents.front() );
79
3.92k
            m_aUserEvents.pop_front();
80
3.92k
        }
81
3.92k
    }
82
83
55.0k
    if (HasUserEvents_NoLock())
84
3.92k
    {
85
3.92k
        bWasEvent = true;
86
3.92k
        m_aProcessingThread = aCurId;
87
88
3.92k
        SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE );
89
3.92k
        do {
90
3.92k
            if (m_aProcessingUserEvents.empty() || aCurId != m_aProcessingThread)
91
0
                break;
92
3.92k
            aEvent = m_aProcessingUserEvents.front();
93
3.92k
            m_aProcessingUserEvents.pop_front();
94
95
            // remember to reset the guard before break or continue the loop
96
3.92k
            aResettableListGuard.unlock();
97
98
3.92k
            if ( !isFrameAlive( aEvent.m_pFrame ) )
99
0
            {
100
0
                if ( aEvent.m_nEvent == SalEvent::UserEvent )
101
0
                    delete static_cast< ImplSVEvent* >( aEvent.m_pData );
102
0
                aResettableListGuard.lock();
103
0
                continue;
104
0
            }
105
106
            /*
107
            * Current policy is that scheduler tasks aren't allowed to throw an exception.
108
            * Because otherwise the exception is caught somewhere totally unrelated.
109
            * TODO Ideally we could capture a proper backtrace and feed this into breakpad,
110
            *   which is do-able, but requires writing some assembly.
111
            * See also Scheduler::CallbackTaskScheduling
112
            */
113
#ifdef IOS
114
            ProcessEvent( aEvent );
115
#else
116
            // the noexcept here means that (a) we abort and (b) debuggers will
117
            // likely trigger at the throw site instead of here, making the debugging
118
            // experience better when something goes wrong.
119
3.92k
            auto process = [&aEvent, this] () noexcept { ProcessEvent(aEvent); };
120
3.92k
            process();
121
3.92k
#endif
122
3.92k
            aResettableListGuard.lock();
123
3.92k
            if (!bHandleAllCurrentEvents)
124
3.92k
                break;
125
3.92k
        }
126
3.92k
        while( true );
127
3.92k
    }
128
129
55.0k
    if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents_NoLock() )
130
3.92k
    {
131
3.92k
        m_bAllUserEventProcessedSignaled = true;
132
3.92k
        TriggerAllUserEventsProcessed();
133
3.92k
    }
134
135
55.0k
    return bWasEvent;
136
55.0k
}
137
138
void SalUserEventList::RemoveEvent( SalFrame* pFrame, void* pData, SalEvent nEvent )
139
0
{
140
0
    SalUserEvent aEvent( pFrame, pData, nEvent );
141
142
0
    std::unique_lock aGuard( m_aUserEventsMutex );
143
0
    auto it = std::find( m_aUserEvents.begin(), m_aUserEvents.end(), aEvent );
144
0
    if ( it != m_aUserEvents.end() )
145
0
    {
146
0
        m_aUserEvents.erase( it );
147
0
    }
148
0
    else
149
0
    {
150
0
        it = std::find( m_aProcessingUserEvents.begin(), m_aProcessingUserEvents.end(), aEvent );
151
0
        if ( it != m_aProcessingUserEvents.end() )
152
0
        {
153
0
            m_aProcessingUserEvents.erase( it );
154
0
        }
155
0
    }
156
157
0
    if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents_NoLock() )
158
0
    {
159
0
        m_bAllUserEventProcessedSignaled = true;
160
0
        TriggerAllUserEventsProcessed();
161
0
    }
162
0
}
163
164
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */