mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 06:21:26 +12:00
107 lines
2.6 KiB
C++
107 lines
2.6 KiB
C++
#pragma once
|
|
|
|
#include "util/types.hpp"
|
|
#include "util/atomic.hpp"
|
|
|
|
struct alignas(16) progress_dialog_string_t
|
|
{
|
|
const char* m_text;
|
|
u32 m_user_count;
|
|
u32 m_update_id;
|
|
|
|
operator const char*() const noexcept
|
|
{
|
|
return m_text;
|
|
}
|
|
};
|
|
|
|
extern atomic_t<progress_dialog_string_t> g_progr;
|
|
extern atomic_t<u32> g_progr_ftotal;
|
|
extern atomic_t<u32> g_progr_fdone;
|
|
extern atomic_t<u32> g_progr_ptotal;
|
|
extern atomic_t<u32> g_progr_pdone;
|
|
extern atomic_t<bool> g_system_progress_canceled;
|
|
extern atomic_t<bool> g_system_progress_stopping;
|
|
|
|
// Initialize progress dialog (can be recursive)
|
|
class scoped_progress_dialog final
|
|
{
|
|
// Saved previous value
|
|
const char* m_prev;
|
|
u32 m_prev_id;
|
|
u32 m_id;
|
|
|
|
public:
|
|
scoped_progress_dialog(const char* text) noexcept
|
|
{
|
|
std::tie(m_prev, m_prev_id, m_id) = g_progr.atomic_op([this, text = ensure(text)](progress_dialog_string_t& progr)
|
|
{
|
|
const char* old = progr.m_text;
|
|
progr.m_user_count++;
|
|
progr.m_update_id++;
|
|
progr.m_text = text;
|
|
|
|
ensure(progr.m_user_count > 1 || !old); // Ensure it was nullptr before first use
|
|
return std::make_tuple(old, progr.m_update_id - 1, progr.m_update_id);
|
|
});
|
|
}
|
|
|
|
scoped_progress_dialog(const scoped_progress_dialog&) = delete;
|
|
|
|
scoped_progress_dialog& operator=(const scoped_progress_dialog&) = delete;
|
|
|
|
scoped_progress_dialog& operator=(const char* text) noexcept
|
|
{
|
|
// This method is destroying the previous value and replacing it with a new one
|
|
std::tie(m_prev, m_prev_id, m_id) = g_progr.atomic_op([this, text = ensure(text)](progress_dialog_string_t& progr)
|
|
{
|
|
if (m_id == progr.m_update_id)
|
|
{
|
|
progr.m_update_id = m_prev_id;
|
|
progr.m_text = m_prev;
|
|
}
|
|
|
|
const char* old = progr.m_text;
|
|
progr.m_text = text;
|
|
progr.m_update_id++;
|
|
|
|
ensure(progr.m_user_count > 0);
|
|
return std::make_tuple(old, progr.m_update_id - 1, progr.m_update_id);
|
|
});
|
|
|
|
return *this;
|
|
}
|
|
|
|
~scoped_progress_dialog() noexcept
|
|
{
|
|
g_progr.atomic_op([this](progress_dialog_string_t& progr)
|
|
{
|
|
if (progr.m_user_count-- == 1)
|
|
{
|
|
// Clean text only on last user
|
|
progr.m_text = nullptr;
|
|
progr.m_update_id = 0;
|
|
}
|
|
else if (m_id == progr.m_update_id)
|
|
{
|
|
// Restore text only if no other updates were made by other threads
|
|
progr.m_text = ensure(m_prev);
|
|
progr.m_update_id = m_prev_id;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
struct progress_dialog_server
|
|
{
|
|
void operator()();
|
|
~progress_dialog_server();
|
|
|
|
static constexpr auto thread_name = "Progress Dialog Server"sv;
|
|
};
|
|
|
|
struct progress_dialog_workaround
|
|
{
|
|
// We don't want to show the native dialog during gameplay.
|
|
atomic_t<bool> show_overlay_message_only = false;
|
|
};
|