HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gui_system.hpp
1// Copyright Take Vos 2020, 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "gui_window.hpp"
8#include "gui_window_win32.hpp"
9#include "gui_system_delegate.hpp"
10#include "../GFX/gfx_system.hpp"
11#include "../GFX/gfx_device.hpp"
12#include "../thread.hpp"
13#include "../unfair_recursive_mutex.hpp"
14#include <span>
15#include <memory>
16#include <mutex>
17#include <thread>
18#include <vector>
19
20namespace tt {
21
25public:
26 static inline os_handle instance;
27
28 thread_id const thread_id;
29
30 gui_system() noexcept : thread_id(current_thread_id()), _delegate() {}
31
32 virtual ~gui_system() {}
33
34 gui_system(const gui_system &) = delete;
35 gui_system &operator=(const gui_system &) = delete;
36 gui_system(gui_system &&) = delete;
37 gui_system &operator=(gui_system &&) = delete;
38
42 virtual void init() noexcept
43 {
44 if (auto delegate = _delegate.lock()) {
45 delegate->init(*this);
46 }
47 }
48
49 virtual void deinit() noexcept
50 {
51 if (auto delegate = _delegate.lock()) {
52 delegate->deinit(*this);
53 }
54 }
55
56 void set_delegate(std::weak_ptr<gui_system_delegate> delegate) noexcept
57 {
58 _delegate = std::move(delegate);
59 }
60
61 virtual void run_from_event_queue(std::function<void()> function) = 0;
62
75 virtual int loop() = 0;
76
77 virtual void exit(int exit_code) = 0;
78
79 gui_window &add_window(std::unique_ptr<gui_window> window);
80
86 template<typename... Args>
87 gui_window &make_window(Args &&...args)
88 {
89 tt_axiom(is_gui_thread());
90
91 // XXX abstract away the _win32 part.
92 auto window = std::make_unique<gui_window_win32>(std::forward<Args>(args)...);
93 window->init();
94
95 return add_window(std::move(window));
96 }
97
101
102 void render(hires_utc_clock::time_point display_time_point)
103 {
104 tt_axiom(is_gui_thread());
105
106 for (auto &window : _windows) {
107 window->render(display_time_point);
108 if (window->is_closed()) {
109 window->deinit();
110 window = nullptr;
111 }
112 }
113 std::erase(_windows, nullptr);
114
115 ttlet num_windows = std::size(_windows);
116 if (num_windows == 0 && num_windows != _previous_num_windows) {
117 // If last_window_closed() creates a new window we should
118 // let it do that before entering the event queue again.
119 // win32 is a bit picky about running without windows.
120 if (auto delegate = _delegate.lock()) {
121 if (auto exit_code = delegate->last_window_closed(*this)) {
122 gui_system::global().exit(*exit_code);
123 }
124 } else {
125 gui_system::global().exit(0);
126 }
127 }
128 _previous_num_windows = num_windows;
129 }
130
133 [[nodiscard]] bool is_gui_thread() const noexcept
134 {
135 return thread_id == current_thread_id();
136 }
137
144 [[nodiscard]] static gui_system &global() noexcept
145 {
146 return *start_subsystem_or_terminate(_global, nullptr, subsystem_init, subsystem_deinit);
147 }
148
149private:
150 static inline std::atomic<gui_system *> _global;
151
153
155 size_t _previous_num_windows;
156
157 [[nodiscard]] static gui_system *subsystem_init() noexcept;
158 static void subsystem_deinit() noexcept;
159};
160
161} // namespace tt
Graphics system.
Definition gui_system.hpp:24
virtual void init() noexcept
Initialize after construction.
Definition gui_system.hpp:42
ssize_t num_windows()
gui_window & make_window(Args &&...args)
Create a new window.
Definition gui_system.hpp:87
bool is_gui_thread() const noexcept
Check if this thread is the same as the gui thread.
Definition gui_system.hpp:133
static gui_system & global() noexcept
Get a reference to the global gui_system.
Definition gui_system.hpp:144
virtual int loop()=0
Start the GUI event loop.
Definition gui_window.hpp:36
T move(T... args)