plusui-native-core 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Core/CMakeLists.txt +190 -7
- package/Core/Features/App/app.cpp +129 -0
- package/Core/Features/App/app.ts +126 -0
- package/Core/Features/Browser/browser.cpp +181 -0
- package/Core/Features/Browser/browser.ts +182 -0
- package/Core/Features/Clipboard/clipboard.cpp +234 -0
- package/Core/Features/Clipboard/clipboard.ts +113 -0
- package/Core/Features/Display/display.cpp +209 -0
- package/Core/Features/Display/display.ts +104 -0
- package/Core/Features/Event/Events.ts +166 -0
- package/Core/Features/Event/events.cpp +200 -0
- package/Core/Features/Keyboard/keyboard.cpp +186 -0
- package/Core/Features/Keyboard/keyboard.ts +175 -0
- package/Core/Features/Menu/context-menu.css +293 -0
- package/Core/Features/Menu/menu.cpp +481 -0
- package/Core/Features/Menu/menu.ts +439 -0
- package/Core/Features/Tray/tray.cpp +310 -0
- package/Core/Features/Tray/tray.ts +68 -0
- package/Core/Features/WebGPU/webgpu.cpp +937 -0
- package/Core/Features/WebGPU/webgpu.ts +1013 -0
- package/Core/Features/WebView/webview.cpp +1052 -0
- package/Core/Features/WebView/webview.ts +510 -0
- package/Core/Features/Window/window.cpp +664 -0
- package/Core/Features/Window/window.ts +142 -0
- package/Core/Features/WindowManager/window_manager.cpp +341 -0
- package/Core/include/plusui/app.hpp +73 -0
- package/Core/include/plusui/browser.hpp +66 -0
- package/Core/include/plusui/clipboard.hpp +41 -0
- package/Core/include/plusui/events.hpp +58 -0
- package/Core/include/{keyboard.hpp → plusui/keyboard.hpp} +21 -44
- package/Core/include/plusui/menu.hpp +153 -0
- package/Core/include/plusui/tray.hpp +93 -0
- package/Core/include/plusui/webgpu.hpp +434 -0
- package/Core/include/plusui/webview.hpp +142 -0
- package/Core/include/plusui/window.hpp +111 -0
- package/Core/include/plusui/window_manager.hpp +57 -0
- package/Core/vendor/WebView2EnvironmentOptions.h +406 -0
- package/Core/vendor/stb_image.h +7988 -0
- package/Core/vendor/webview.h +618 -510
- package/Core/vendor/webview2.h +52079 -0
- package/README.md +19 -0
- package/package.json +12 -15
- package/Core/include/app.hpp +0 -121
- package/Core/include/menu.hpp +0 -79
- package/Core/include/tray.hpp +0 -81
- package/Core/include/window.hpp +0 -106
- package/Core/src/app.cpp +0 -311
- package/Core/src/display.cpp +0 -424
- package/Core/src/tray.cpp +0 -275
- package/Core/src/window.cpp +0 -528
- package/dist/index.d.ts +0 -205
- package/dist/index.js +0 -198
- package/src/index.ts +0 -574
- /package/Core/include/{display.hpp → plusui/display.hpp} +0 -0
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
#include <iostream>
|
|
2
|
+
#include <map>
|
|
3
|
+
#include <plusui/display.hpp>
|
|
4
|
+
#include <plusui/window.hpp>
|
|
5
|
+
|
|
6
|
+
#ifdef _WIN32
|
|
7
|
+
#include <windows.h>
|
|
8
|
+
#elif defined(__APPLE__)
|
|
9
|
+
#include <Cocoa/Cocoa.h>
|
|
10
|
+
#include <objc/objc-runtime.h>
|
|
11
|
+
#else
|
|
12
|
+
#include <gtk/gtk.h>
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
#include <stb_image.h>
|
|
16
|
+
|
|
17
|
+
namespace plusui {
|
|
18
|
+
|
|
19
|
+
struct Window::Impl {
|
|
20
|
+
void *nativeWindow = nullptr;
|
|
21
|
+
WindowConfig config;
|
|
22
|
+
WindowState state;
|
|
23
|
+
|
|
24
|
+
std::vector<MoveCallback> moveCallbacks;
|
|
25
|
+
std::vector<ResizeCallback> resizeCallbacks;
|
|
26
|
+
std::vector<CloseCallback> closeCallbacks;
|
|
27
|
+
std::vector<FocusCallback> focusCallbacks;
|
|
28
|
+
std::vector<StateCallback> stateCallbacks;
|
|
29
|
+
|
|
30
|
+
#ifdef _WIN32
|
|
31
|
+
HWND hwnd = nullptr;
|
|
32
|
+
WNDPROC originalProc = nullptr;
|
|
33
|
+
|
|
34
|
+
static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
|
|
35
|
+
Impl *impl = nullptr;
|
|
36
|
+
if (msg == WM_NCCREATE) {
|
|
37
|
+
auto cs = (LPCREATESTRUCT)lp;
|
|
38
|
+
impl = (Impl *)cs->lpCreateParams;
|
|
39
|
+
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)impl);
|
|
40
|
+
} else {
|
|
41
|
+
impl = (Impl *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (impl) {
|
|
45
|
+
switch (msg) {
|
|
46
|
+
case WM_MOVE: {
|
|
47
|
+
int x = (int)(short)LOWORD(lp);
|
|
48
|
+
int y = (int)(short)HIWORD(lp);
|
|
49
|
+
impl->state.x = x;
|
|
50
|
+
impl->state.y = y;
|
|
51
|
+
for (auto &cb : impl->moveCallbacks)
|
|
52
|
+
cb(x, y);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case WM_SIZE: {
|
|
56
|
+
int width = LOWORD(lp);
|
|
57
|
+
int height = HIWORD(lp);
|
|
58
|
+
impl->state.width = width;
|
|
59
|
+
impl->state.height = height;
|
|
60
|
+
for (auto &cb : impl->resizeCallbacks)
|
|
61
|
+
cb(width, height);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case WM_CLOSE:
|
|
65
|
+
for (auto &cb : impl->closeCallbacks)
|
|
66
|
+
cb();
|
|
67
|
+
break;
|
|
68
|
+
case WM_SETFOCUS:
|
|
69
|
+
impl->state.isFocused = true;
|
|
70
|
+
for (auto &cb : impl->focusCallbacks)
|
|
71
|
+
cb(true);
|
|
72
|
+
break;
|
|
73
|
+
case WM_KILLFOCUS:
|
|
74
|
+
impl->state.isFocused = false;
|
|
75
|
+
for (auto &cb : impl->focusCallbacks)
|
|
76
|
+
cb(false);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return DefWindowProc(hwnd, msg, wp, lp);
|
|
81
|
+
}
|
|
82
|
+
#endif
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
Window::Window() : pImpl(std::shared_ptr<Impl>(new Impl())) {}
|
|
86
|
+
|
|
87
|
+
Window::~Window() = default;
|
|
88
|
+
|
|
89
|
+
Window Window::create(const WindowConfig &config) {
|
|
90
|
+
Window w;
|
|
91
|
+
w.pImpl->config = config;
|
|
92
|
+
|
|
93
|
+
#ifdef _WIN32
|
|
94
|
+
WNDCLASSEXW wc = {};
|
|
95
|
+
wc.cbSize = sizeof(WNDCLASSEXW);
|
|
96
|
+
wc.lpfnWndProc = Impl::wndProc;
|
|
97
|
+
wc.hInstance = GetModuleHandle(nullptr);
|
|
98
|
+
wc.lpszClassName = L"PLUSUI_WINDOW";
|
|
99
|
+
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
100
|
+
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
101
|
+
RegisterClassExW(&wc);
|
|
102
|
+
|
|
103
|
+
DWORD style = 0;
|
|
104
|
+
DWORD exStyle = 0;
|
|
105
|
+
|
|
106
|
+
if (config.decorations) {
|
|
107
|
+
style = WS_OVERLAPPEDWINDOW;
|
|
108
|
+
if (!config.resizable)
|
|
109
|
+
style &= ~WS_THICKFRAME;
|
|
110
|
+
if (!config.minimizable)
|
|
111
|
+
style &= ~WS_MINIMIZEBOX;
|
|
112
|
+
if (!config.closable)
|
|
113
|
+
style &= ~WS_SYSMENU;
|
|
114
|
+
} else {
|
|
115
|
+
// Frameless window
|
|
116
|
+
style = WS_POPUP;
|
|
117
|
+
if (config.resizable)
|
|
118
|
+
style |= WS_THICKFRAME;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (config.transparent) {
|
|
122
|
+
exStyle = WS_EX_LAYERED;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (config.skipTaskbar) {
|
|
126
|
+
exStyle |= WS_EX_TOOLWINDOW;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
std::wstring wideTitle(config.title.begin(), config.title.end());
|
|
130
|
+
w.pImpl->hwnd = CreateWindowExW(
|
|
131
|
+
exStyle, L"PLUSUI_WINDOW", wideTitle.c_str(), style,
|
|
132
|
+
config.x >= 0 ? config.x : CW_USEDEFAULT,
|
|
133
|
+
config.y >= 0 ? config.y : CW_USEDEFAULT, config.width, config.height,
|
|
134
|
+
nullptr, nullptr, GetModuleHandle(nullptr), w.pImpl.get());
|
|
135
|
+
|
|
136
|
+
w.pImpl->nativeWindow = (void *)w.pImpl->hwnd;
|
|
137
|
+
w.pImpl->state.width = config.width;
|
|
138
|
+
w.pImpl->state.height = config.height;
|
|
139
|
+
|
|
140
|
+
if (config.center) {
|
|
141
|
+
RECT screen;
|
|
142
|
+
SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0);
|
|
143
|
+
int x = (screen.right - config.width) / 2;
|
|
144
|
+
int y = (screen.bottom - config.height) / 2;
|
|
145
|
+
SetWindowPos(w.pImpl->hwnd, nullptr, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (config.alwaysOnTop) {
|
|
149
|
+
SetWindowPos(w.pImpl->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
|
|
150
|
+
SWP_NOMOVE | SWP_NOSIZE);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
#elif defined(__APPLE__)
|
|
154
|
+
NSWindow *nswin = [[NSWindow alloc]
|
|
155
|
+
initWithContentRect:NSMakeRect(config.x >= 0 ? config.x : 100,
|
|
156
|
+
config.y >= 0 ? config.y : 100,
|
|
157
|
+
config.width, config.height)
|
|
158
|
+
styleMask:(config.resizable ? NSWindowStyleMaskResizable : 0) |
|
|
159
|
+
NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
|
160
|
+
(config.minimizable ? NSWindowStyleMaskMiniaturizable
|
|
161
|
+
: 0)backing:NSBackingStoreBuffered
|
|
162
|
+
defer:NO];
|
|
163
|
+
|
|
164
|
+
[nswin setTitle:[NSString stringWithUTF8String:config.title.c_str()]];
|
|
165
|
+
[nswin setReleasedWhenClosed:NO];
|
|
166
|
+
|
|
167
|
+
if (config.center) {
|
|
168
|
+
[nswin center];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (config.alwaysOnTop) {
|
|
172
|
+
[nswin setLevel:NSFloatingWindowLevel];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
w.pImpl->nativeWindow = (__bridge void *)nswin;
|
|
176
|
+
|
|
177
|
+
#else
|
|
178
|
+
gtk_init_check(0, nullptr);
|
|
179
|
+
|
|
180
|
+
GtkWindow *gtkwin = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
|
|
181
|
+
gtk_window_set_title(gtkwin, config.title.c_str());
|
|
182
|
+
gtk_window_set_default_size(gtkwin, config.width, config.height);
|
|
183
|
+
|
|
184
|
+
if (config.x >= 0 && config.y >= 0) {
|
|
185
|
+
gtk_window_move(gtkwin, config.x, config.y);
|
|
186
|
+
} else if (config.center) {
|
|
187
|
+
gtk_window_set_position(gtkwin, GTK_WIN_POS_CENTER);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!config.resizable) {
|
|
191
|
+
gtk_window_set_resizable(gtkwin, FALSE);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (config.alwaysOnTop) {
|
|
195
|
+
gtk_window_set_keep_above(gtkwin, TRUE);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
w.pImpl->nativeWindow = (void *)gtkwin;
|
|
199
|
+
#endif
|
|
200
|
+
|
|
201
|
+
return w;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
void Window::setTitle(const std::string &title) {
|
|
205
|
+
pImpl->config.title = title;
|
|
206
|
+
#ifdef _WIN32
|
|
207
|
+
if (pImpl->hwnd) {
|
|
208
|
+
std::wstring wideTitle(title.begin(), title.end());
|
|
209
|
+
SetWindowTextW(pImpl->hwnd, wideTitle.c_str());
|
|
210
|
+
}
|
|
211
|
+
#elif defined(__APPLE__)
|
|
212
|
+
if (pImpl->nativeWindow) {
|
|
213
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
214
|
+
[nswin setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
|
215
|
+
}
|
|
216
|
+
#else
|
|
217
|
+
if (pImpl->nativeWindow) {
|
|
218
|
+
gtk_window_set_title(GTK_WINDOW(pImpl->nativeWindow), title.c_str());
|
|
219
|
+
}
|
|
220
|
+
#endif
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
std::string Window::getTitle() const { return pImpl->config.title; }
|
|
224
|
+
|
|
225
|
+
void Window::setSize(int width, int height) {
|
|
226
|
+
pImpl->config.width = width;
|
|
227
|
+
pImpl->config.height = height;
|
|
228
|
+
#ifdef _WIN32
|
|
229
|
+
if (pImpl->hwnd)
|
|
230
|
+
SetWindowPos(pImpl->hwnd, nullptr, 0, 0, width, height,
|
|
231
|
+
SWP_NOZORDER | SWP_NOMOVE);
|
|
232
|
+
#elif defined(__APPLE__)
|
|
233
|
+
if (pImpl->nativeWindow) {
|
|
234
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
235
|
+
[nswin setContentSize:NSMakeSize(width, height)];
|
|
236
|
+
}
|
|
237
|
+
#else
|
|
238
|
+
if (pImpl->nativeWindow) {
|
|
239
|
+
gtk_window_resize(GTK_WINDOW(pImpl->nativeWindow), width, height);
|
|
240
|
+
}
|
|
241
|
+
#endif
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
void Window::getSize(int &width, int &height) const {
|
|
245
|
+
width = pImpl->state.width;
|
|
246
|
+
height = pImpl->state.height;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
void Window::setMinSize(int minWidth, int minHeight) {
|
|
250
|
+
pImpl->config.minWidth = minWidth;
|
|
251
|
+
pImpl->config.minHeight = minHeight;
|
|
252
|
+
#ifdef _WIN32
|
|
253
|
+
if (pImpl->hwnd) {
|
|
254
|
+
SetWindowLongPtr(pImpl->hwnd, GWL_STYLE,
|
|
255
|
+
GetWindowLong(pImpl->hwnd, GWL_STYLE) | WS_THICKFRAME);
|
|
256
|
+
}
|
|
257
|
+
#endif
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
void Window::setMaxSize(int maxWidth, int maxHeight) {
|
|
261
|
+
pImpl->config.maxWidth = maxWidth;
|
|
262
|
+
pImpl->config.maxHeight = maxHeight;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
void Window::setPosition(int x, int y) {
|
|
266
|
+
pImpl->config.x = x;
|
|
267
|
+
pImpl->config.y = y;
|
|
268
|
+
#ifdef _WIN32
|
|
269
|
+
if (pImpl->hwnd)
|
|
270
|
+
SetWindowPos(pImpl->hwnd, nullptr, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
271
|
+
#elif defined(__APPLE__)
|
|
272
|
+
if (pImpl->nativeWindow) {
|
|
273
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
274
|
+
[nswin setFrameOrigin:NSMakePoint(x, y)];
|
|
275
|
+
}
|
|
276
|
+
#else
|
|
277
|
+
if (pImpl->nativeWindow) {
|
|
278
|
+
gtk_window_move(GTK_WINDOW(pImpl->nativeWindow), x, y);
|
|
279
|
+
}
|
|
280
|
+
#endif
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
void Window::getPosition(int &x, int &y) const {
|
|
284
|
+
x = pImpl->state.x;
|
|
285
|
+
y = pImpl->state.y;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
void Window::center() {
|
|
289
|
+
#ifdef _WIN32
|
|
290
|
+
if (pImpl->hwnd) {
|
|
291
|
+
RECT rc, screen;
|
|
292
|
+
GetWindowRect(pImpl->hwnd, &rc);
|
|
293
|
+
SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0);
|
|
294
|
+
int x = (screen.right - (rc.right - rc.left)) / 2;
|
|
295
|
+
int y = (screen.bottom - (rc.bottom - rc.top)) / 2;
|
|
296
|
+
SetWindowPos(pImpl->hwnd, nullptr, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
297
|
+
}
|
|
298
|
+
#elif defined(__APPLE__)
|
|
299
|
+
if (pImpl->nativeWindow) {
|
|
300
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
301
|
+
[nswin center];
|
|
302
|
+
}
|
|
303
|
+
#else
|
|
304
|
+
if (pImpl->nativeWindow) {
|
|
305
|
+
gtk_window_set_position(GTK_WINDOW(pImpl->nativeWindow),
|
|
306
|
+
GTK_WIN_POS_CENTER);
|
|
307
|
+
}
|
|
308
|
+
#endif
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
void Window::setFullscreen(bool enabled) {
|
|
312
|
+
bool wasFullscreen = pImpl->state.isFullscreen;
|
|
313
|
+
pImpl->config.fullscreen = enabled;
|
|
314
|
+
pImpl->state.isFullscreen = enabled;
|
|
315
|
+
pImpl->state.isHidden = false;
|
|
316
|
+
|
|
317
|
+
#ifdef _WIN32
|
|
318
|
+
if (pImpl->hwnd) {
|
|
319
|
+
if (enabled) {
|
|
320
|
+
SetWindowLongPtr(pImpl->hwnd, GWL_STYLE,
|
|
321
|
+
GetWindowLong(pImpl->hwnd, GWL_STYLE) &
|
|
322
|
+
~WS_OVERLAPPEDWINDOW);
|
|
323
|
+
SetWindowPos(pImpl->hwnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
|
|
324
|
+
GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW);
|
|
325
|
+
} else {
|
|
326
|
+
SetWindowLongPtr(pImpl->hwnd, GWL_STYLE,
|
|
327
|
+
GetWindowLong(pImpl->hwnd, GWL_STYLE) |
|
|
328
|
+
WS_OVERLAPPEDWINDOW);
|
|
329
|
+
SetWindowPos(pImpl->hwnd, nullptr, 0, 0, 0, 0,
|
|
330
|
+
SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
#elif defined(__APPLE__)
|
|
334
|
+
if (pImpl->nativeWindow) {
|
|
335
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
336
|
+
if (enabled) {
|
|
337
|
+
[nswin toggleFullScreen:nil];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
#else
|
|
341
|
+
if (pImpl->nativeWindow) {
|
|
342
|
+
if (enabled) {
|
|
343
|
+
gtk_window_fullscreen(GTK_WINDOW(pImpl->nativeWindow));
|
|
344
|
+
} else {
|
|
345
|
+
gtk_window_unfullscreen(GTK_WINDOW(pImpl->nativeWindow));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
#endif
|
|
349
|
+
|
|
350
|
+
if (wasFullscreen != enabled) {
|
|
351
|
+
for (auto &cb : pImpl->stateCallbacks)
|
|
352
|
+
cb(pImpl->state);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
bool Window::isFullscreen() const { return pImpl->state.isFullscreen; }
|
|
357
|
+
|
|
358
|
+
void Window::minimize() {
|
|
359
|
+
bool wasMinimized = pImpl->state.isMinimized;
|
|
360
|
+
pImpl->state.isMinimized = true;
|
|
361
|
+
pImpl->state.isHidden = false;
|
|
362
|
+
|
|
363
|
+
#ifdef _WIN32
|
|
364
|
+
if (pImpl->hwnd)
|
|
365
|
+
ShowWindow(pImpl->hwnd, SW_MINIMIZE);
|
|
366
|
+
#elif defined(__APPLE__)
|
|
367
|
+
if (pImpl->nativeWindow) {
|
|
368
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
369
|
+
[nswin miniaturize:nil];
|
|
370
|
+
}
|
|
371
|
+
#else
|
|
372
|
+
if (pImpl->nativeWindow) {
|
|
373
|
+
gtk_window_iconify(GTK_WINDOW(pImpl->nativeWindow));
|
|
374
|
+
}
|
|
375
|
+
#endif
|
|
376
|
+
|
|
377
|
+
if (!wasMinimized) {
|
|
378
|
+
for (auto &cb : pImpl->stateCallbacks)
|
|
379
|
+
cb(pImpl->state);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
void Window::maximize() {
|
|
384
|
+
bool wasMaximized = pImpl->state.isMaximized;
|
|
385
|
+
pImpl->state.isMaximized = true;
|
|
386
|
+
pImpl->state.isHidden = false;
|
|
387
|
+
|
|
388
|
+
#ifdef _WIN32
|
|
389
|
+
if (pImpl->hwnd)
|
|
390
|
+
ShowWindow(pImpl->hwnd, SW_MAXIMIZE);
|
|
391
|
+
#elif defined(__APPLE__)
|
|
392
|
+
if (pImpl->nativeWindow) {
|
|
393
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
394
|
+
[nswin zoom:nil];
|
|
395
|
+
}
|
|
396
|
+
#else
|
|
397
|
+
if (pImpl->nativeWindow) {
|
|
398
|
+
gtk_window_maximize(GTK_WINDOW(pImpl->nativeWindow));
|
|
399
|
+
}
|
|
400
|
+
#endif
|
|
401
|
+
|
|
402
|
+
if (!wasMaximized) {
|
|
403
|
+
for (auto &cb : pImpl->stateCallbacks)
|
|
404
|
+
cb(pImpl->state);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
void Window::restore() {
|
|
409
|
+
bool wasMinimized = pImpl->state.isMinimized;
|
|
410
|
+
bool wasMaximized = pImpl->state.isMaximized;
|
|
411
|
+
pImpl->state.isMinimized = false;
|
|
412
|
+
pImpl->state.isMaximized = false;
|
|
413
|
+
pImpl->state.isHidden = false;
|
|
414
|
+
|
|
415
|
+
#ifdef _WIN32
|
|
416
|
+
if (pImpl->hwnd)
|
|
417
|
+
ShowWindow(pImpl->hwnd, SW_RESTORE);
|
|
418
|
+
#elif defined(__APPLE__)
|
|
419
|
+
if (pImpl->nativeWindow) {
|
|
420
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
421
|
+
[nswin deminiaturize:nil];
|
|
422
|
+
}
|
|
423
|
+
#else
|
|
424
|
+
if (pImpl->nativeWindow) {
|
|
425
|
+
gtk_window_unmaximize(GTK_WINDOW(pImpl->nativeWindow));
|
|
426
|
+
gtk_window_deiconify(GTK_WINDOW(pImpl->nativeWindow));
|
|
427
|
+
}
|
|
428
|
+
#endif
|
|
429
|
+
|
|
430
|
+
if (wasMinimized || wasMaximized) {
|
|
431
|
+
for (auto &cb : pImpl->stateCallbacks)
|
|
432
|
+
cb(pImpl->state);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
bool Window::isMaximized() const { return pImpl->state.isMaximized; }
|
|
437
|
+
|
|
438
|
+
bool Window::isMinimized() const { return pImpl->state.isMinimized; }
|
|
439
|
+
|
|
440
|
+
void Window::show() {
|
|
441
|
+
bool wasHidden = pImpl->state.isHidden;
|
|
442
|
+
pImpl->state.isVisible = true;
|
|
443
|
+
pImpl->state.isHidden = false;
|
|
444
|
+
|
|
445
|
+
#ifdef _WIN32
|
|
446
|
+
if (pImpl->hwnd)
|
|
447
|
+
ShowWindow(pImpl->hwnd, SW_SHOW);
|
|
448
|
+
#elif defined(__APPLE__)
|
|
449
|
+
if (pImpl->nativeWindow) {
|
|
450
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
451
|
+
[nswin orderFront:nil];
|
|
452
|
+
}
|
|
453
|
+
#else
|
|
454
|
+
if (pImpl->nativeWindow) {
|
|
455
|
+
gtk_widget_show(GTK_WIDGET(pImpl->nativeWindow));
|
|
456
|
+
}
|
|
457
|
+
#endif
|
|
458
|
+
|
|
459
|
+
// Fire state change event if hidden state changed
|
|
460
|
+
if (wasHidden) {
|
|
461
|
+
for (auto &cb : pImpl->stateCallbacks)
|
|
462
|
+
cb(pImpl->state);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
void Window::hide() {
|
|
467
|
+
bool wasVisible = pImpl->state.isVisible;
|
|
468
|
+
pImpl->state.isVisible = false;
|
|
469
|
+
pImpl->state.isHidden = true;
|
|
470
|
+
|
|
471
|
+
#ifdef _WIN32
|
|
472
|
+
if (pImpl->hwnd)
|
|
473
|
+
ShowWindow(pImpl->hwnd, SW_HIDE);
|
|
474
|
+
#elif defined(__APPLE__)
|
|
475
|
+
if (pImpl->nativeWindow) {
|
|
476
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
477
|
+
[nswin orderOut:nil];
|
|
478
|
+
}
|
|
479
|
+
#else
|
|
480
|
+
if (pImpl->nativeWindow) {
|
|
481
|
+
gtk_widget_hide(GTK_WIDGET(pImpl->nativeWindow));
|
|
482
|
+
}
|
|
483
|
+
#endif
|
|
484
|
+
|
|
485
|
+
// Fire state change event if visibility changed
|
|
486
|
+
if (wasVisible) {
|
|
487
|
+
for (auto &cb : pImpl->stateCallbacks)
|
|
488
|
+
cb(pImpl->state);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
bool Window::isVisible() const { return pImpl->state.isVisible; }
|
|
493
|
+
|
|
494
|
+
bool Window::isHidden() const { return pImpl->state.isHidden; }
|
|
495
|
+
|
|
496
|
+
void Window::focus() {
|
|
497
|
+
#ifdef _WIN32
|
|
498
|
+
if (pImpl->hwnd)
|
|
499
|
+
SetFocus(pImpl->hwnd);
|
|
500
|
+
#elif defined(__APPLE__)
|
|
501
|
+
if (pImpl->nativeWindow) {
|
|
502
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
503
|
+
[nswin makeKeyAndOrderFront:nil];
|
|
504
|
+
}
|
|
505
|
+
#else
|
|
506
|
+
if (pImpl->nativeWindow) {
|
|
507
|
+
gtk_window_present(GTK_WINDOW(pImpl->nativeWindow));
|
|
508
|
+
}
|
|
509
|
+
#endif
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
bool Window::isFocused() const { return pImpl->state.isFocused; }
|
|
513
|
+
|
|
514
|
+
void Window::setAlwaysOnTop(bool enabled) {
|
|
515
|
+
pImpl->config.alwaysOnTop = enabled;
|
|
516
|
+
#ifdef _WIN32
|
|
517
|
+
if (pImpl->hwnd) {
|
|
518
|
+
SetWindowPos(pImpl->hwnd, enabled ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0,
|
|
519
|
+
0, SWP_NOMOVE | SWP_NOSIZE);
|
|
520
|
+
}
|
|
521
|
+
#elif defined(__APPLE__)
|
|
522
|
+
if (pImpl->nativeWindow) {
|
|
523
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
524
|
+
[nswin setLevel:enabled ? NSFloatingWindowLevel : NSNormalWindowLevel];
|
|
525
|
+
}
|
|
526
|
+
#else
|
|
527
|
+
if (pImpl->nativeWindow) {
|
|
528
|
+
gtk_window_set_keep_above(GTK_WINDOW(pImpl->nativeWindow), enabled);
|
|
529
|
+
}
|
|
530
|
+
#endif
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
void Window::setResizable(bool enabled) {
|
|
534
|
+
pImpl->config.resizable = enabled;
|
|
535
|
+
#ifdef _WIN32
|
|
536
|
+
if (pImpl->hwnd) {
|
|
537
|
+
SetWindowLongPtr(
|
|
538
|
+
pImpl->hwnd, GWL_STYLE,
|
|
539
|
+
enabled ? GetWindowLong(pImpl->hwnd, GWL_STYLE) | WS_THICKFRAME
|
|
540
|
+
: GetWindowLong(pImpl->hwnd, GWL_STYLE) & ~WS_THICKFRAME);
|
|
541
|
+
}
|
|
542
|
+
#elif defined(__APPLE__)
|
|
543
|
+
// Handled in create
|
|
544
|
+
#else
|
|
545
|
+
if (pImpl->nativeWindow) {
|
|
546
|
+
gtk_window_set_resizable(GTK_WINDOW(pImpl->nativeWindow), enabled);
|
|
547
|
+
}
|
|
548
|
+
#endif
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
void Window::setDecorations(bool enabled) {
|
|
552
|
+
#ifdef _WIN32
|
|
553
|
+
if (pImpl->hwnd) {
|
|
554
|
+
SetWindowLongPtr(pImpl->hwnd, GWL_STYLE,
|
|
555
|
+
enabled
|
|
556
|
+
? GetWindowLong(pImpl->hwnd, GWL_STYLE) | WS_CAPTION
|
|
557
|
+
: GetWindowLong(pImpl->hwnd, GWL_STYLE) & ~WS_CAPTION);
|
|
558
|
+
}
|
|
559
|
+
#elif defined(__APPLE__)
|
|
560
|
+
if (pImpl->nativeWindow) {
|
|
561
|
+
NSWindow *nswin = (__bridge NSWindow *)pImpl->nativeWindow;
|
|
562
|
+
[nswin setStyleMask:enabled ? [nswin styleMask] | NSWindowStyleMaskTitled
|
|
563
|
+
: [nswin styleMask] & ~NSWindowStyleMaskTitled];
|
|
564
|
+
}
|
|
565
|
+
#else
|
|
566
|
+
if (pImpl->nativeWindow) {
|
|
567
|
+
// GTK handles this differently
|
|
568
|
+
}
|
|
569
|
+
#endif
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
void Window::setSkipTaskbar(bool enabled) {
|
|
573
|
+
#ifdef _WIN32
|
|
574
|
+
if (pImpl->hwnd) {
|
|
575
|
+
SetWindowLongPtr(
|
|
576
|
+
pImpl->hwnd, GWL_EXSTYLE,
|
|
577
|
+
enabled ? GetWindowLong(pImpl->hwnd, GWL_EXSTYLE) | WS_EX_TOOLWINDOW
|
|
578
|
+
: GetWindowLong(pImpl->hwnd, GWL_EXSTYLE) & ~WS_EX_TOOLWINDOW);
|
|
579
|
+
}
|
|
580
|
+
#endif
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
void Window::setOpacity(double opacity) {
|
|
584
|
+
pImpl->config.opacity = opacity;
|
|
585
|
+
#ifdef _WIN32
|
|
586
|
+
if (pImpl->hwnd) {
|
|
587
|
+
BYTE alpha = static_cast<BYTE>(opacity * 255);
|
|
588
|
+
SetWindowLongPtr(pImpl->hwnd, GWL_EXSTYLE,
|
|
589
|
+
GetWindowLong(pImpl->hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
|
|
590
|
+
SetLayeredWindowAttributes(pImpl->hwnd, 0, alpha, LWA_ALPHA);
|
|
591
|
+
}
|
|
592
|
+
#endif
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
void Window::setIconFromMemory(const unsigned char *data, size_t size) {
|
|
596
|
+
#ifdef _WIN32
|
|
597
|
+
if (pImpl->hwnd) {
|
|
598
|
+
int width, height, channels;
|
|
599
|
+
unsigned char *pixels =
|
|
600
|
+
stbi_load_from_memory(data, (int)size, &width, &height, &channels, 4);
|
|
601
|
+
if (pixels) {
|
|
602
|
+
BITMAPINFO bmi = {};
|
|
603
|
+
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
604
|
+
bmi.bmiHeader.biWidth = width;
|
|
605
|
+
bmi.bmiHeader.biHeight = -height;
|
|
606
|
+
bmi.bmiHeader.biPlanes = 1;
|
|
607
|
+
bmi.bmiHeader.biBitCount = 32;
|
|
608
|
+
bmi.bmiHeader.biCompression = BI_RGB;
|
|
609
|
+
|
|
610
|
+
void *bits = nullptr;
|
|
611
|
+
HBITMAP hbm =
|
|
612
|
+
CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0);
|
|
613
|
+
if (hbm && bits) {
|
|
614
|
+
// Convert RGBA to BGRA
|
|
615
|
+
for (int i = 0; i < width * height; ++i) {
|
|
616
|
+
((uint8_t *)bits)[i * 4 + 0] = pixels[i * 4 + 2];
|
|
617
|
+
((uint8_t *)bits)[i * 4 + 1] = pixels[i * 4 + 1];
|
|
618
|
+
((uint8_t *)bits)[i * 4 + 2] = pixels[i * 4 + 0];
|
|
619
|
+
((uint8_t *)bits)[i * 4 + 3] = pixels[i * 4 + 3];
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
ICONINFO ii = {};
|
|
623
|
+
ii.fIcon = TRUE;
|
|
624
|
+
ii.hbmColor = hbm;
|
|
625
|
+
ii.hbmMask = hbm;
|
|
626
|
+
|
|
627
|
+
HICON hIcon = CreateIconIndirect(&ii);
|
|
628
|
+
if (hIcon) {
|
|
629
|
+
SendMessage(pImpl->hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
|
|
630
|
+
SendMessage(pImpl->hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
|
|
631
|
+
}
|
|
632
|
+
DeleteObject(hbm);
|
|
633
|
+
}
|
|
634
|
+
stbi_image_free(pixels);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
#endif
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
WindowState Window::getState() const { return pImpl->state; }
|
|
641
|
+
|
|
642
|
+
void Window::onMove(MoveCallback callback) {
|
|
643
|
+
pImpl->moveCallbacks.push_back(callback);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
void Window::onResize(ResizeCallback callback) {
|
|
647
|
+
pImpl->resizeCallbacks.push_back(callback);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
void Window::onClose(CloseCallback callback) {
|
|
651
|
+
pImpl->closeCallbacks.push_back(callback);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
void Window::onFocus(FocusCallback callback) {
|
|
655
|
+
pImpl->focusCallbacks.push_back(callback);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
void Window::onStateChange(StateCallback callback) {
|
|
659
|
+
pImpl->stateCallbacks.push_back(callback);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
void *Window::nativeHandle() const { return pImpl->nativeWindow; }
|
|
663
|
+
|
|
664
|
+
} // namespace plusui
|