-
Notifications
You must be signed in to change notification settings - Fork 2
/
WindowHost.h
330 lines (300 loc) · 10.8 KB
/
WindowHost.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#pragma once
#include "WindowHostRely.h"
#include "WindowEvent.h"
#include "SystemCommon/MiniLogger.h"
#include "SystemCommon/LoopBase.h"
#include "SystemCommon/PromiseTask.h"
#include "common/AtomicUtil.hpp"
#include "common/TimeUtil.hpp"
#if COMMON_COMPILER_MSVC
# pragma warning(push)
# pragma warning(disable:4275 4251)
#endif
namespace xziar::gui
{
class WindowHost_;
using WindowHost = std::shared_ptr<WindowHost_>;
namespace detail
{
class WindowManager;
class WindowManagerWin32;
class WindowManagerXCB;
class WindowManagerCocoa;
}
struct CreateInfo
{
std::u16string Title;
uint32_t Width = 1280, Height = 720;
uint16_t TargetFPS = 0;
};
class WindowBackend
{
private:
struct Pimpl;
std::unique_ptr<Pimpl> Impl;
virtual void OnPrepare() noexcept;
virtual void OnMessageLoop() = 0;
virtual void OnTerminate() noexcept;
virtual bool RequestStop() noexcept = 0;
protected:
WindowBackend(bool supportNewThread) noexcept;
WDHOSTAPI void CheckIfInited();
virtual void OnInitialize(const void* info);
virtual void OnDeInitialize() noexcept;
public:
virtual ~WindowBackend();
void Init()
{
CheckIfInited();
OnInitialize(nullptr);
}
WDHOSTAPI bool Run(bool isNewThread, common::BasicPromise<void>* pms = nullptr);
WDHOSTAPI bool Stop();
[[nodiscard]] virtual std::string_view Name() const noexcept = 0;
[[nodiscard]] virtual bool CheckFeature(std::string_view feat) const noexcept = 0;
[[nodiscard]] WDHOSTAPI static common::span<WindowBackend* const> GetBackends() noexcept;
template<typename T>
[[nodiscard]] static T* GetBackend() noexcept
{
static_assert(std::is_base_of_v<WindowBackend, T>);
for (const auto& backend : GetBackends())
{
if (const auto ld = dynamic_cast<const T*>(backend); ld)
return ld;
}
return nullptr;
}
[[nodiscard]] static const WindowBackend* GetBackend(std::string_view name) noexcept
{
for (const auto& backend : GetBackends())
{
if (backend->Name() == name)
return backend;
}
return nullptr;
}
[[nodiscard]] static const WindowBackend* GetBackend(common::span<const std::string_view> features) noexcept
{
for (const auto& backend : GetBackends())
{
bool match = true;
for (const auto& feat : features)
{
if (!backend->CheckFeature(feat))
{
match = false;
break;
}
}
if (match)
return backend;
}
return nullptr;
}
virtual WindowHost Create(const CreateInfo& info = {}) = 0;
};
template<typename... Args>
class WindowEventDelegate;
class CallbackToken
{
template<typename...> friend class WindowEventDelegate;
void* CallbackPtr = nullptr;
uint32_t ID = 0;
};
template<typename... Args>
class WindowEventDelegate
{
friend WindowHost_;
void* Target;
bool (*Handler)(void*, void*, CallbackToken*);
constexpr WindowEventDelegate(void* target, bool (*handler)(void*, void*, CallbackToken*)) noexcept :
Target(target), Handler(handler) { }
public:
template<typename T>
CallbackToken operator+=(T&& callback)
{
std::function<void(WindowHost_&, Args...)> cb;
if constexpr (std::is_invocable_v<T, WindowHost_&, Args...>)
cb = std::forward<T>(callback);
else if constexpr (std::is_invocable_v<T, Args...>)
cb = [real = std::forward<T>(callback)](WindowHost_&, Args... args) { real(args...); };
else if constexpr (std::is_invocable_v<T>)
cb = [real = std::forward<T>(callback)](WindowHost_&, Args...) { real(); };
else
static_assert(!common::AlwaysTrue<T>, "unsupported callback type");
CallbackToken token;
Handler(Target, &cb, &token);
return token;
}
bool operator-=(CallbackToken token)
{
return Handler(Target, nullptr, &token);
}
};
class WDHOSTAPI WindowHost_ :
private common::loop::LoopBase,
public std::enable_shared_from_this<WindowHost_>
{
friend detail::WindowManager;
friend detail::WindowManagerWin32;
friend detail::WindowManagerXCB;
friend detail::WindowManagerCocoa;
private:
struct Pimpl;
std::unique_ptr<Pimpl> Impl;
detail::WindowManager& Manager;
std::u16string Title;
int32_t Width, Height;
event::Position LastPos, LeftBtnPos;
event::MouseButton PressedButton = event::MouseButton::None;
event::ModifierKeys Modifiers = event::ModifierKeys::None;
bool NeedCheckDrag = true, IsMouseDragging = false, MouseHasLeft = true;
[[nodiscard]] const std::any* GetWindowData_(std::string_view name) const noexcept;
void SetWindowData_(std::string_view name, std::any&& data) const noexcept;
bool OnStart(const common::ThreadObject&, std::any& cookie) noexcept final;
LoopAction OnLoop() override final;
void OnStop() noexcept override final;
void Initialize();
void RefreshMouseButton(event::MouseButton pressed) noexcept;
protected:
WindowHost_(detail::WindowManager& manager, const CreateInfo& info) noexcept;
using LoopBase::Wakeup;
bool HandleInvoke() noexcept;
// below callbacks are called inside UI thread (Window Loop)
virtual void OnOpen() noexcept;
virtual LoopAction OnLoopPass();
virtual void OnDisplay() noexcept;
// below callbacks are called inside Manager thread (Main Loop)
[[nodiscard]] virtual bool OnClose() noexcept;
virtual void OnResize(int32_t width, int32_t height) noexcept;
virtual void OnDPIChange(float x, float y) noexcept;
virtual void OnMouseEnter(event::Position pos) noexcept;
virtual void OnMouseLeave() noexcept;
virtual void OnMouseButton(event::MouseButton changedBtn, bool isPress) noexcept;
virtual void OnMouseButtonChange(event::MouseButton btn) noexcept;
virtual void OnMouseMove(event::Position pos) noexcept;
virtual void OnMouseDrag(event::Position pos) noexcept;
virtual void OnMouseScroll(event::Position pos, float dh, float dv) noexcept;
virtual void OnKeyDown(event::CombinedKey key) noexcept;
virtual void OnKeyUp(event::CombinedKey key) noexcept;
virtual void OnDropFile(event::Position pos, common::StringPool<char16_t>&& namepool,
std::vector<common::StringPiece<char16_t>>&& names) noexcept;
public:
~WindowHost_() override;
event::ModifierKeys GetModifiers() const noexcept { return Modifiers; }
event::Position GetLastPosition() const noexcept { return LastPos; }
template<typename T>
const T* GetWindowData(std::string_view name) const noexcept
{
return std::any_cast<T>(GetWindowData_(name));
}
template<typename T>
void SetWindowData(std::string_view name, const T& data) const noexcept
{
SetWindowData_(name, std::any{ data });
}
void RemoveWindowData(std::string_view name) const noexcept;
// below delegates are called inside UI thread (Window Loop)
WindowEventDelegate<> Openning() const noexcept;
WindowEventDelegate<> Displaying() const noexcept;
WindowEventDelegate<> Closed() const noexcept;
// below delegates are called inside Manager thread (Main Loop)
WindowEventDelegate<bool&> Closing() const noexcept;
WindowEventDelegate<int32_t, int32_t> Resizing() const noexcept;
WindowEventDelegate<> Minimizing() const noexcept;
WindowEventDelegate<float, float> DPIChanging() const noexcept;
WindowEventDelegate<const event::MouseEvent&> MouseEnter() const noexcept;
WindowEventDelegate<const event::MouseEvent&> MouseLeave() const noexcept;
WindowEventDelegate<const event::MouseButtonEvent&> MouseButtonDown() const noexcept;
WindowEventDelegate<const event::MouseButtonEvent&> MouseButtonUp() const noexcept;
WindowEventDelegate<const event::MouseMoveEvent&> MouseMove() const noexcept;
WindowEventDelegate<const event::MouseDragEvent&> MouseDrag() const noexcept;
WindowEventDelegate<const event::MouseScrollEvent&> MouseScroll() const noexcept;
WindowEventDelegate<const event::KeyEvent&> KeyDown() const noexcept;
WindowEventDelegate<const event::KeyEvent&> KeyUp() const noexcept;
WindowEventDelegate<const event::DropFileEvent&> DropFile() const noexcept;
// below delegates are called from any thread
void Show(const std::function<std::any(std::string_view)>& provider = {});
void Close();
WindowHost GetSelf();
void SetTitle(const std::u16string_view title);
void Invoke(std::function<void(void)> task);
void InvokeUI(std::function<void(WindowHost_&)> task);
virtual void Invalidate();
void SetTargetFPS(uint16_t fps) noexcept;
};
class Win32Backend : public WindowBackend
{
protected:
using WindowBackend::WindowBackend;
public:
struct Win32CreateInfo : public CreateInfo
{
};
class Win32WdHost : public WindowHost_
{
protected:
using WindowHost_::WindowHost_;
public:
[[nodiscard]] virtual void* GetHDC() const noexcept = 0;
[[nodiscard]] virtual void* GetHWND() const noexcept = 0;
};
using WindowBackend::Create;
[[nodiscard]] virtual std::shared_ptr<Win32WdHost> Create(const Win32CreateInfo& info = {}) = 0;
};
using Win32WdHost = std::shared_ptr<Win32Backend::Win32WdHost>;
class XCBBackend : public WindowBackend
{
protected:
using WindowBackend::WindowBackend;
public:
struct XCBCreateInfo : public CreateInfo
{
};
struct XCBInitInfo
{
std::string DisplayName;
bool UsePureXCB = false;
};
class XCBWdHost : public WindowHost_
{
protected:
using WindowHost_::WindowHost_;
public:
[[nodiscard]] virtual uint32_t GetWindow() const noexcept = 0;
};
void Init(const XCBInitInfo& info)
{
CheckIfInited();
OnInitialize(&info);
}
using WindowBackend::Create;
[[nodiscard]] virtual std::shared_ptr<XCBWdHost> Create(const XCBCreateInfo& info = {}) = 0;
[[nodiscard]] virtual void* GetDisplay() const noexcept = 0;
[[nodiscard]] virtual void* GetConnection() const noexcept = 0;
[[nodiscard]] virtual int32_t GetDefaultScreen() const noexcept = 0;
};
using XCBWdHost = std::shared_ptr<XCBBackend::XCBWdHost>;
class CocoaBackend : public WindowBackend
{
protected:
using WindowBackend::WindowBackend;
public:
struct CocoaCreateInfo : public CreateInfo
{
};
class CocoaWdHost : public WindowHost_
{
protected:
using WindowHost_::WindowHost_;
public:
[[nodiscard]] virtual void* GetWindow() const noexcept = 0;
};
using WindowBackend::Create;
[[nodiscard]] virtual std::shared_ptr<CocoaWdHost> Create(const CocoaCreateInfo& info = {}) = 0;
};
using XCBWdHost = std::shared_ptr<XCBBackend::XCBWdHost>;
}
#if COMMON_COMPILER_MSVC
# pragma warning(pop)
#endif