xe::ui control for hosting a turbobadger UI.
This commit is contained in:
@@ -77,10 +77,11 @@ LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_PAINT: {
|
||||
invalidated_ = false;
|
||||
ValidateRect(hWnd, nullptr);
|
||||
SCOPE_profile_cpu_i("gpu", "xe::gpu::gl4::WGLControl::WM_PAINT");
|
||||
{
|
||||
GLContextLock context_lock(&context_);
|
||||
wglSwapIntervalEXT(0);
|
||||
|
||||
float clear_color[] = {rand() / (float)RAND_MAX, 1.0f, 0, 1.0f};
|
||||
glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color);
|
||||
@@ -100,6 +101,7 @@ LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
SCOPE_profile_cpu_i("gpu", "xe::gpu::gl4::WGLControl::SwapBuffers");
|
||||
SwapBuffers(context_.dc());
|
||||
}
|
||||
return 0;
|
||||
} break;
|
||||
}
|
||||
return Win32Control::WndProc(hWnd, message, wParam, lParam);
|
||||
|
||||
@@ -21,6 +21,7 @@ class Loop {
|
||||
virtual ~Loop() = default;
|
||||
|
||||
virtual void Post(std::function<void()> fn) = 0;
|
||||
virtual void PostDelayed(std::function<void()> fn, uint64_t delay_millis) = 0;
|
||||
|
||||
virtual void Quit() = 0;
|
||||
virtual void AwaitQuit() = 0;
|
||||
|
||||
@@ -121,10 +121,13 @@ void Win32Control::OnResize(UIEvent& e) {
|
||||
}
|
||||
|
||||
void Win32Control::Invalidate() {
|
||||
if (invalidated_) {
|
||||
return;
|
||||
}
|
||||
invalidated_ = true;
|
||||
InvalidateRect(hwnd_, nullptr, FALSE);
|
||||
for (auto& child_control : children_) {
|
||||
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||
win32_control->Invalidate();
|
||||
child_control->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,8 +237,15 @@ LRESULT Win32Control::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_PAINT:
|
||||
case WM_PAINT: {
|
||||
if (flags_ & kFlagOwnPaint) {
|
||||
return 0; // ignore
|
||||
}
|
||||
invalidated_ = false;
|
||||
auto e = UIEvent(this);
|
||||
OnPaint(e);
|
||||
break;
|
||||
}
|
||||
case WM_ERASEBKGND:
|
||||
if (flags_ & kFlagOwnPaint) {
|
||||
return 0; // ignore
|
||||
|
||||
@@ -54,7 +54,8 @@ class Win32Control : public Control {
|
||||
virtual LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
HWND hwnd_;
|
||||
HWND hwnd_ = nullptr;
|
||||
bool invalidated_ = true;
|
||||
|
||||
private:
|
||||
bool HandleMouse(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
@@ -28,6 +28,8 @@ class PostedFn {
|
||||
};
|
||||
|
||||
Win32Loop::Win32Loop() : thread_id_(0) {
|
||||
timer_queue_ = CreateTimerQueue();
|
||||
|
||||
xe::threading::Fence init_fence;
|
||||
thread_ = std::thread([&init_fence, this]() {
|
||||
xe::threading::set_name("Win32 Loop");
|
||||
@@ -49,6 +51,14 @@ Win32Loop::Win32Loop() : thread_id_(0) {
|
||||
Win32Loop::~Win32Loop() {
|
||||
Quit();
|
||||
thread_.join();
|
||||
|
||||
DeleteTimerQueueEx(timer_queue_, INVALID_HANDLE_VALUE);
|
||||
std::lock_guard<xe::mutex> lock(pending_timers_mutex_);
|
||||
while (!pending_timers_.empty()) {
|
||||
auto timer = pending_timers_.back();
|
||||
pending_timers_.pop_back();
|
||||
delete timer;
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Loop::ThreadMain() {
|
||||
@@ -82,6 +92,38 @@ void Win32Loop::Post(std::function<void()> fn) {
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Loop::TimerQueueCallback(void* context, uint8_t) {
|
||||
auto timer = reinterpret_cast<PendingTimer*>(context);
|
||||
auto loop = timer->loop;
|
||||
auto fn = std::move(timer->fn);
|
||||
DeleteTimerQueueTimer(timer->timer_queue, timer->timer_handle, NULL);
|
||||
{
|
||||
std::lock_guard<xe::mutex> lock(loop->pending_timers_mutex_);
|
||||
loop->pending_timers_.remove(timer);
|
||||
}
|
||||
delete timer;
|
||||
loop->Post(std::move(fn));
|
||||
}
|
||||
|
||||
void Win32Loop::PostDelayed(std::function<void()> fn, uint64_t delay_millis) {
|
||||
if (!delay_millis) {
|
||||
Post(std::move(fn));
|
||||
return;
|
||||
}
|
||||
auto timer = new PendingTimer();
|
||||
timer->loop = this;
|
||||
timer->timer_queue = timer_queue_;
|
||||
timer->fn = std::move(fn);
|
||||
{
|
||||
std::lock_guard<xe::mutex> lock(pending_timers_mutex_);
|
||||
pending_timers_.push_back(timer);
|
||||
}
|
||||
CreateTimerQueueTimer(&timer->timer_handle, timer_queue_,
|
||||
WAITORTIMERCALLBACK(TimerQueueCallback), timer,
|
||||
DWORD(delay_millis), 0,
|
||||
WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE);
|
||||
}
|
||||
|
||||
void Win32Loop::Quit() {
|
||||
assert_true(thread_id_ != 0);
|
||||
PostThreadMessage(thread_id_, kWmWin32LoopQuit,
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
#ifndef XENIA_UI_WIN32_WIN32_LOOP_H_
|
||||
#define XENIA_UI_WIN32_WIN32_LOOP_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
@@ -29,16 +29,30 @@ class Win32Loop : public Loop {
|
||||
~Win32Loop() override;
|
||||
|
||||
void Post(std::function<void()> fn) override;
|
||||
void PostDelayed(std::function<void()> fn, uint64_t delay_millis) override;
|
||||
|
||||
void Quit() override;
|
||||
void AwaitQuit() override;
|
||||
|
||||
private:
|
||||
struct PendingTimer {
|
||||
Win32Loop* loop;
|
||||
HANDLE timer_queue;
|
||||
HANDLE timer_handle;
|
||||
std::function<void()> fn;
|
||||
};
|
||||
|
||||
void ThreadMain();
|
||||
|
||||
static void TimerQueueCallback(void* context, uint8_t);
|
||||
|
||||
std::thread thread_;
|
||||
DWORD thread_id_;
|
||||
xe::threading::Fence quit_fence_;
|
||||
|
||||
HANDLE timer_queue_;
|
||||
xe::mutex pending_timers_mutex_;
|
||||
std::list<PendingTimer*> pending_timers_;
|
||||
};
|
||||
|
||||
} // namespace win32
|
||||
|
||||
Reference in New Issue
Block a user