windowpp 0.1.1
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/bin/windowpp.js +86 -0
- package/cmake/embed_assets.py +144 -0
- package/framework/CMakeLists.txt +176 -0
- package/framework/include/windowpp/windowpp.h +704 -0
- package/framework/src/AppData/API/AppData.ts +137 -0
- package/framework/src/AppData/appdata_bridge.h +138 -0
- package/framework/src/AppData/appdata_manager.cpp +126 -0
- package/framework/src/AppData/appdata_manager.h +3 -0
- package/framework/src/FileSystem/API/FileSystem.ts +389 -0
- package/framework/src/FileSystem/Linux/filesearch.cpp +148 -0
- package/framework/src/FileSystem/Linux/readfile.cpp +79 -0
- package/framework/src/FileSystem/Linux/savefile.cpp +333 -0
- package/framework/src/FileSystem/MacOS/filesearch.cpp +149 -0
- package/framework/src/FileSystem/MacOS/readfile.cpp +80 -0
- package/framework/src/FileSystem/MacOS/savefile.cpp +264 -0
- package/framework/src/FileSystem/Windows/filesearch.cpp +195 -0
- package/framework/src/FileSystem/Windows/readfile.cpp +122 -0
- package/framework/src/FileSystem/Windows/savefile.cpp +290 -0
- package/framework/src/FileSystem/file_index_service.cpp +262 -0
- package/framework/src/FileSystem/file_index_service.h +55 -0
- package/framework/src/FileSystem/filesystem_bridge.h +243 -0
- package/framework/src/FileSystem/filesystem_handler.h +93 -0
- package/framework/src/FileSystem/filesystem_json.h +241 -0
- package/framework/src/FileSystem/filesystem_search_service.cpp +414 -0
- package/framework/src/FileSystem/filesystem_search_service.h +94 -0
- package/framework/src/Input/API/Input.ts +161 -0
- package/framework/src/Input/Linux/linux_key_utils.h +135 -0
- package/framework/src/Input/MacOS/macos_key_utils.h +137 -0
- package/framework/src/Input/Windows/win32_key_utils.h +199 -0
- package/framework/src/Input/input_bridge.h +192 -0
- package/framework/src/Input/input_service.cpp +584 -0
- package/framework/src/Input/input_service.h +21 -0
- package/framework/src/application.cpp +29 -0
- package/framework/src/common/hit_test.cpp +40 -0
- package/framework/src/common/image_loader.cpp +24 -0
- package/framework/src/common/paths.cpp +75 -0
- package/framework/src/filedrop/filedrop.cpp +316 -0
- package/framework/src/filedrop/filedrop.css +421 -0
- package/framework/src/filedrop/filedrop.hpp +92 -0
- package/framework/src/filedrop/filedrop.ts +183 -0
- package/framework/src/platform/API/App.ts +156 -0
- package/framework/src/platform/API/Window.ts +249 -0
- package/framework/src/platform/linux/app_linux.cpp +256 -0
- package/framework/src/platform/linux/app_linux.h +64 -0
- package/framework/src/platform/linux/linux_helpers.cpp +26 -0
- package/framework/src/platform/linux/linux_helpers.h +19 -0
- package/framework/src/platform/linux/tray_linux.cpp +21 -0
- package/framework/src/platform/linux/tray_linux.h +26 -0
- package/framework/src/platform/linux/window_linux.cpp +256 -0
- package/framework/src/platform/linux/window_linux.h +70 -0
- package/framework/src/platform/macos/app_macos.h +59 -0
- package/framework/src/platform/macos/app_macos.mm +223 -0
- package/framework/src/platform/macos/macos_helpers.h +21 -0
- package/framework/src/platform/macos/tray_macos.h +22 -0
- package/framework/src/platform/macos/tray_macos.mm +53 -0
- package/framework/src/platform/macos/window_macos.h +74 -0
- package/framework/src/platform/macos/window_macos.mm +318 -0
- package/framework/src/platform/platform_bridge.h +514 -0
- package/framework/src/platform/platform_factory.cpp +33 -0
- package/framework/src/platform/platform_factory.h +19 -0
- package/framework/src/platform/win32/app_win32.cpp +572 -0
- package/framework/src/platform/win32/app_win32.h +83 -0
- package/framework/src/platform/win32/tray_win32.cpp +57 -0
- package/framework/src/platform/win32/tray_win32.h +30 -0
- package/framework/src/platform/win32/win32_helpers.h +61 -0
- package/framework/src/platform/win32/window_win32.cpp +267 -0
- package/framework/src/platform/win32/window_win32.h +79 -0
- package/framework/src/renderer/webgpu.h +128 -0
- package/framework/src/renderer/webview/include/WebView2.h +48014 -0
- package/framework/src/renderer/webview/include/WebView2EnvironmentOptions.h +342 -0
- package/framework/src/renderer/webview/webview.h +13 -0
- package/framework/src/renderer/webview/webview_linux.cpp +392 -0
- package/framework/src/renderer/webview/webview_macos.mm +388 -0
- package/framework/src/renderer/webview/webview_win32.cpp +688 -0
- package/framework/src/renderer/webview/x64/WebView2Loader.dll +0 -0
- package/framework/src/renderer/webview/x64/WebView2Loader.lib +0 -0
- package/framework/src/renderer/webview/x64/WebView2LoaderStatic.lib +0 -0
- package/lib/build.js +112 -0
- package/lib/create.js +283 -0
- package/lib/dev.js +155 -0
- package/package.json +24 -0
- package/scripts/publish.js +67 -0
- package/scripts/sync-framework.js +73 -0
- package/templates/solid/CMakeLists.txt +56 -0
- package/templates/solid/frontend/package.json +22 -0
- package/templates/solid/frontend/vite.config.ts +25 -0
- package/templates/solid/main.cpp +72 -0
- package/templates/solid/package.json +12 -0
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// WindowPP — Cross-Platform Native Window Library
|
|
5
|
+
//
|
|
6
|
+
// One header. Two config structs. Zero boilerplate.
|
|
7
|
+
//
|
|
8
|
+
// Supports: Windows (Win32), macOS (Cocoa), Linux (X11 + XCB)
|
|
9
|
+
// Features: Frameless/transparent windows with proper resize handles,
|
|
10
|
+
// system tray, startup registration, file drop, multi-window.
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
#include <string>
|
|
14
|
+
#include <functional>
|
|
15
|
+
#include <vector>
|
|
16
|
+
#include <cstdint>
|
|
17
|
+
#include <memory>
|
|
18
|
+
#include <unordered_map>
|
|
19
|
+
|
|
20
|
+
namespace wpp {
|
|
21
|
+
|
|
22
|
+
// ─── Forward Declarations ────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
class Application;
|
|
25
|
+
class Window;
|
|
26
|
+
class AppDataManager;
|
|
27
|
+
struct KeyEvent;
|
|
28
|
+
|
|
29
|
+
namespace input {
|
|
30
|
+
|
|
31
|
+
enum class Key {
|
|
32
|
+
Unknown,
|
|
33
|
+
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
|
34
|
+
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
|
35
|
+
Digit0, Digit1, Digit2, Digit3, Digit4,
|
|
36
|
+
Digit5, Digit6, Digit7, Digit8, Digit9,
|
|
37
|
+
Space,
|
|
38
|
+
Enter,
|
|
39
|
+
Escape,
|
|
40
|
+
Tab,
|
|
41
|
+
Backspace,
|
|
42
|
+
Delete,
|
|
43
|
+
Insert,
|
|
44
|
+
Home,
|
|
45
|
+
End,
|
|
46
|
+
PageUp,
|
|
47
|
+
PageDown,
|
|
48
|
+
Left,
|
|
49
|
+
Right,
|
|
50
|
+
Up,
|
|
51
|
+
Down,
|
|
52
|
+
CapsLock,
|
|
53
|
+
Shift,
|
|
54
|
+
Control,
|
|
55
|
+
Alt,
|
|
56
|
+
Meta,
|
|
57
|
+
F1,
|
|
58
|
+
F2,
|
|
59
|
+
F3,
|
|
60
|
+
F4,
|
|
61
|
+
F5,
|
|
62
|
+
F6,
|
|
63
|
+
F7,
|
|
64
|
+
F8,
|
|
65
|
+
F9,
|
|
66
|
+
F10,
|
|
67
|
+
F11,
|
|
68
|
+
F12
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
enum class KeyEventType {
|
|
72
|
+
KeyDown,
|
|
73
|
+
KeyUp
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
struct Shortcut {
|
|
77
|
+
Key key = Key::Unknown;
|
|
78
|
+
bool ctrl = false;
|
|
79
|
+
bool shift = false;
|
|
80
|
+
bool alt = false;
|
|
81
|
+
bool meta = false;
|
|
82
|
+
std::string text;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
struct ShortcutOptions {
|
|
86
|
+
bool global = false;
|
|
87
|
+
bool trigger_on_key_up = false;
|
|
88
|
+
bool allow_repeat = false;
|
|
89
|
+
std::string window_id;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
class Service {
|
|
93
|
+
public:
|
|
94
|
+
using ListenerId = uint64_t;
|
|
95
|
+
using KeyListener = std::function<void(const KeyEvent& event)>;
|
|
96
|
+
using ShortcutHandler = std::function<void(const KeyEvent& event)>;
|
|
97
|
+
|
|
98
|
+
static Service& instance();
|
|
99
|
+
|
|
100
|
+
ListenerId add_key_listener(KeyListener listener);
|
|
101
|
+
void remove_key_listener(ListenerId id);
|
|
102
|
+
|
|
103
|
+
Shortcut parse_shortcut(const std::string& text) const;
|
|
104
|
+
std::string format_shortcut(const Shortcut& shortcut) const;
|
|
105
|
+
|
|
106
|
+
void register_shortcut(const std::string& id,
|
|
107
|
+
const std::string& shortcut,
|
|
108
|
+
ShortcutHandler handler,
|
|
109
|
+
ShortcutOptions options = {});
|
|
110
|
+
void register_app_shortcut(const std::string& id,
|
|
111
|
+
const std::string& shortcut,
|
|
112
|
+
ShortcutHandler handler,
|
|
113
|
+
const std::string& window_id = "") {
|
|
114
|
+
register_shortcut(id, shortcut, std::move(handler), ShortcutOptions{false, false, false, window_id});
|
|
115
|
+
}
|
|
116
|
+
void register_global_shortcut(const std::string& id,
|
|
117
|
+
const std::string& shortcut,
|
|
118
|
+
ShortcutHandler handler) {
|
|
119
|
+
register_shortcut(id, shortcut, std::move(handler), ShortcutOptions{true, false, false, {}});
|
|
120
|
+
}
|
|
121
|
+
void unregister_shortcut(const std::string& id);
|
|
122
|
+
void clear_shortcuts();
|
|
123
|
+
|
|
124
|
+
bool is_pressed(Key key) const;
|
|
125
|
+
std::vector<Key> pressed_keys() const;
|
|
126
|
+
|
|
127
|
+
private:
|
|
128
|
+
Service() = default;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
Service& service();
|
|
132
|
+
std::string key_to_string(Key key);
|
|
133
|
+
|
|
134
|
+
} // namespace input
|
|
135
|
+
|
|
136
|
+
struct AppDataEntry {
|
|
137
|
+
std::string name;
|
|
138
|
+
std::string path;
|
|
139
|
+
bool is_dir = false;
|
|
140
|
+
bool is_symlink = false;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// ─── AppData Types ───────────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
struct SeedEntry {
|
|
146
|
+
std::string relative_path;
|
|
147
|
+
std::string content;
|
|
148
|
+
bool overwrite = false;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
class AppDataManager {
|
|
152
|
+
public:
|
|
153
|
+
explicit AppDataManager(const std::string& app_name);
|
|
154
|
+
|
|
155
|
+
const std::string& root() const;
|
|
156
|
+
std::string path(const std::string& relative = "") const;
|
|
157
|
+
|
|
158
|
+
bool exists(const std::string& relative = "") const;
|
|
159
|
+
std::string read_text(const std::string& relative) const;
|
|
160
|
+
void write_text(const std::string& relative, const std::string& content);
|
|
161
|
+
void append_text(const std::string& relative, const std::string& content);
|
|
162
|
+
void delete_file(const std::string& relative);
|
|
163
|
+
void create_dir(const std::string& relative, bool recursive = true);
|
|
164
|
+
void remove_dir(const std::string& relative, bool recursive = false);
|
|
165
|
+
std::vector<AppDataEntry> read_dir(const std::string& relative = "") const;
|
|
166
|
+
|
|
167
|
+
void ensure_dirs(const std::vector<std::string>& dirs);
|
|
168
|
+
void seed_file(const std::string& relative_path,
|
|
169
|
+
const std::string& content,
|
|
170
|
+
bool overwrite = false);
|
|
171
|
+
void seed_files(const std::vector<SeedEntry>& entries);
|
|
172
|
+
|
|
173
|
+
private:
|
|
174
|
+
std::string root_;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// ─── Enums ───────────────────────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
enum class WindowState {
|
|
180
|
+
Normal,
|
|
181
|
+
Minimized,
|
|
182
|
+
Maximized,
|
|
183
|
+
Fullscreen,
|
|
184
|
+
Hidden
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
enum class CursorType {
|
|
188
|
+
Arrow,
|
|
189
|
+
Hand,
|
|
190
|
+
IBeam,
|
|
191
|
+
Crosshair,
|
|
192
|
+
ResizeNS,
|
|
193
|
+
ResizeEW,
|
|
194
|
+
ResizeNWSE,
|
|
195
|
+
ResizeNESW,
|
|
196
|
+
Move,
|
|
197
|
+
NotAllowed,
|
|
198
|
+
Wait
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
enum class HitTestRegion {
|
|
202
|
+
Client, // Normal content area
|
|
203
|
+
Caption, // Draggable titlebar region
|
|
204
|
+
ResizeTop,
|
|
205
|
+
ResizeBottom,
|
|
206
|
+
ResizeLeft,
|
|
207
|
+
ResizeRight,
|
|
208
|
+
ResizeTopLeft,
|
|
209
|
+
ResizeTopRight,
|
|
210
|
+
ResizeBottomLeft,
|
|
211
|
+
ResizeBottomRight,
|
|
212
|
+
Close,
|
|
213
|
+
Minimize,
|
|
214
|
+
Maximize
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
enum class TrayClickType {
|
|
218
|
+
Left,
|
|
219
|
+
Right,
|
|
220
|
+
Double
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// ─── Data Types ──────────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
struct Point {
|
|
226
|
+
int x = 0;
|
|
227
|
+
int y = 0;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
struct Size {
|
|
231
|
+
int width = 0;
|
|
232
|
+
int height = 0;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
struct Rect {
|
|
236
|
+
int x = 0;
|
|
237
|
+
int y = 0;
|
|
238
|
+
int width = 0;
|
|
239
|
+
int height = 0;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
struct Color {
|
|
243
|
+
uint8_t r = 0;
|
|
244
|
+
uint8_t g = 0;
|
|
245
|
+
uint8_t b = 0;
|
|
246
|
+
uint8_t a = 255;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
struct MonitorInfo {
|
|
250
|
+
std::string name;
|
|
251
|
+
Rect bounds; // Full monitor area
|
|
252
|
+
Rect work_area; // Excluding taskbar/dock
|
|
253
|
+
float scale_factor; // DPI scaling (1.0 = 96dpi)
|
|
254
|
+
bool is_primary;
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// ─── Event Types ─────────────────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
struct MouseEvent {
|
|
260
|
+
Point position; // Relative to window
|
|
261
|
+
Point global_position;
|
|
262
|
+
int button; // 0=left, 1=right, 2=middle
|
|
263
|
+
int clicks; // 1=single, 2=double
|
|
264
|
+
int scroll_delta_x;
|
|
265
|
+
int scroll_delta_y;
|
|
266
|
+
bool ctrl;
|
|
267
|
+
bool shift;
|
|
268
|
+
bool alt;
|
|
269
|
+
bool meta;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
struct KeyEvent {
|
|
273
|
+
input::Key key = input::Key::Unknown;
|
|
274
|
+
input::KeyEventType type = input::KeyEventType::KeyDown;
|
|
275
|
+
int keycode; // Platform virtual keycode
|
|
276
|
+
uint32_t scancode;
|
|
277
|
+
std::string key_name; // "A", "Enter", "Escape", etc.
|
|
278
|
+
bool ctrl;
|
|
279
|
+
bool shift;
|
|
280
|
+
bool alt;
|
|
281
|
+
bool meta;
|
|
282
|
+
bool is_repeat;
|
|
283
|
+
bool is_global = false;
|
|
284
|
+
std::string window_id;
|
|
285
|
+
std::vector<input::Key> pressed_keys;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
struct DropEvent {
|
|
289
|
+
std::vector<std::string> paths; // File/folder paths
|
|
290
|
+
Point position;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
struct ResizeEvent {
|
|
294
|
+
Size old_size;
|
|
295
|
+
Size new_size;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
struct MoveEvent {
|
|
299
|
+
Point old_position;
|
|
300
|
+
Point new_position;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// ─── WebView ─────────────────────────────────────────────────────────────────
|
|
304
|
+
|
|
305
|
+
// Response returned by a custom scheme handler (see WebViewConfig::scheme_handler).
|
|
306
|
+
struct SchemeResponse {
|
|
307
|
+
std::vector<uint8_t> body;
|
|
308
|
+
std::string content_type;
|
|
309
|
+
int status = 200;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
struct WebViewConfig {
|
|
313
|
+
bool enabled = false;
|
|
314
|
+
bool frameless = false;
|
|
315
|
+
bool scrollbars = false;
|
|
316
|
+
bool file_drop = false;
|
|
317
|
+
std::string initial_url;
|
|
318
|
+
std::string initial_html;
|
|
319
|
+
bool devtools = false;
|
|
320
|
+
std::function<void(std::string)> on_load_finished;
|
|
321
|
+
std::function<void(std::string)> on_message;
|
|
322
|
+
|
|
323
|
+
// Optional: register a custom URI scheme (e.g. "app") so the WebView can
|
|
324
|
+
// serve embedded assets without an external server. When set, the WebView
|
|
325
|
+
// intercepts every request whose scheme matches `custom_scheme` and calls
|
|
326
|
+
// `scheme_handler` with the URL path (e.g. "/index.html"). Return a
|
|
327
|
+
// SchemeResponse with the body and MIME type. For SPA routing, return
|
|
328
|
+
// index.html for any path that isn't a known asset.
|
|
329
|
+
//
|
|
330
|
+
// Usage in main.cpp:
|
|
331
|
+
// config.custom_scheme = "app";
|
|
332
|
+
// config.scheme_handler = [](const std::string& path) { ... };
|
|
333
|
+
// config.initial_url = "app://localhost/index.html";
|
|
334
|
+
std::string custom_scheme;
|
|
335
|
+
std::function<SchemeResponse(const std::string& path)> scheme_handler;
|
|
336
|
+
|
|
337
|
+
// Optional: directory for WebView2/WKWebView/WebKitGTK profile data
|
|
338
|
+
// (cookies, cache, localStorage, IndexedDB, etc.).
|
|
339
|
+
// Defaults to empty — WebView2 creates a folder next to the exe;
|
|
340
|
+
// set to wpp::paths::app_data_dir(app_name) + "/WebView" to keep
|
|
341
|
+
// all profile data in the OS-standard application data location.
|
|
342
|
+
std::string user_data_dir;
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
class WebView {
|
|
346
|
+
public:
|
|
347
|
+
virtual ~WebView() = default;
|
|
348
|
+
virtual void load_url(const std::string& url) = 0;
|
|
349
|
+
virtual void load_html(const std::string& html) = 0;
|
|
350
|
+
virtual void execute_script(const std::string& script) = 0;
|
|
351
|
+
virtual void send_message(const std::string& message) = 0;
|
|
352
|
+
virtual void go_back() = 0;
|
|
353
|
+
virtual void go_forward() = 0;
|
|
354
|
+
virtual void reload() = 0;
|
|
355
|
+
virtual void close() = 0;
|
|
356
|
+
virtual void resize(int width, int height) = 0;
|
|
357
|
+
virtual void set_drag_drop_enabled(bool enabled) = 0;
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// ─── Menu ────────────────────────────────────────────────────────────────────
|
|
361
|
+
|
|
362
|
+
struct MenuItem {
|
|
363
|
+
std::string label;
|
|
364
|
+
std::string shortcut; // e.g. "Ctrl+Q"
|
|
365
|
+
std::function<void()> on_click;
|
|
366
|
+
bool enabled = true;
|
|
367
|
+
bool checked = false;
|
|
368
|
+
bool is_separator = false;
|
|
369
|
+
std::vector<MenuItem> submenu;
|
|
370
|
+
|
|
371
|
+
static MenuItem Separator() {
|
|
372
|
+
MenuItem m;
|
|
373
|
+
m.is_separator = true;
|
|
374
|
+
return m;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// ─── Tray Config ─────────────────────────────────────────────────────────────
|
|
379
|
+
|
|
380
|
+
struct TrayConfig {
|
|
381
|
+
std::string icon_path; // Path to tray icon (PNG, ICO)
|
|
382
|
+
std::string tooltip;
|
|
383
|
+
std::vector<MenuItem> menu;
|
|
384
|
+
std::function<void(TrayClickType)> on_click;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
388
|
+
// STRUCT 1: APP_CONFIG — Application-level settings
|
|
389
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
390
|
+
|
|
391
|
+
struct AppConfig {
|
|
392
|
+
// ── Identity ──
|
|
393
|
+
std::string name = "WindowPP App";
|
|
394
|
+
std::string version = "1.0.0";
|
|
395
|
+
std::string identifier = "com.app.windowpp"; // Reverse domain (macOS bundle ID, Linux .desktop)
|
|
396
|
+
|
|
397
|
+
// ── App Icon ──
|
|
398
|
+
std::string icon_path = ""; // Path to app icon (PNG/ICO) — embedded into binary on build
|
|
399
|
+
|
|
400
|
+
// ── System Tray ──
|
|
401
|
+
bool tray_enabled = false;
|
|
402
|
+
TrayConfig tray;
|
|
403
|
+
|
|
404
|
+
// ── Behavior ──
|
|
405
|
+
bool single_instance = false; // Only allow one running instance
|
|
406
|
+
bool run_on_startup = false; // Register with OS auto-start
|
|
407
|
+
bool quit_on_last_close = true; // Exit app when all windows closed
|
|
408
|
+
bool hide_on_close = false; // Hide to tray instead of quitting
|
|
409
|
+
|
|
410
|
+
// ── Appearance ──
|
|
411
|
+
bool dark_mode = false; // Prefer dark theme (where supported)
|
|
412
|
+
bool high_dpi_aware = true; // Enable DPI scaling
|
|
413
|
+
|
|
414
|
+
// ── Lifecycle Callbacks ──
|
|
415
|
+
std::function<void()> on_ready; // App initialized
|
|
416
|
+
std::function<void()> on_quit; // About to quit
|
|
417
|
+
std::function<bool()> on_quit_requested; // Return false to cancel
|
|
418
|
+
std::function<void(const std::string&)> on_open_file; // OS asked us to open a file
|
|
419
|
+
std::function<void(const std::string&)> on_open_url; // OS asked us to open a URL (custom protocol)
|
|
420
|
+
|
|
421
|
+
// ── Custom Protocol ──
|
|
422
|
+
std::string protocol_scheme = ""; // e.g. "myapp" → handles "myapp://..."
|
|
423
|
+
|
|
424
|
+
// ── Logging ──
|
|
425
|
+
bool verbose_logging = false;
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
429
|
+
// STRUCT 2: WINDOW_CONFIG — Per-window settings
|
|
430
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
431
|
+
|
|
432
|
+
struct WindowConfig {
|
|
433
|
+
// ── Identity ──
|
|
434
|
+
std::string id = "main"; // Unique window ID: "main", "settings", "child", etc.
|
|
435
|
+
std::string title = "Window";
|
|
436
|
+
|
|
437
|
+
// ── Geometry ──
|
|
438
|
+
int width = 800;
|
|
439
|
+
int height = 600;
|
|
440
|
+
int x = -1; // -1 = center on screen
|
|
441
|
+
int y = -1;
|
|
442
|
+
int min_width = 0; // 0 = no minimum
|
|
443
|
+
int min_height = 0;
|
|
444
|
+
int max_width = 0; // 0 = no maximum
|
|
445
|
+
int max_height = 0;
|
|
446
|
+
|
|
447
|
+
// ── Chrome ──
|
|
448
|
+
bool frameless = false; // No OS-provided window frame
|
|
449
|
+
bool titlebar = true; // Show native titlebar (ignored if frameless)
|
|
450
|
+
bool resizable = true;
|
|
451
|
+
bool closable = true;
|
|
452
|
+
bool minimizable = true;
|
|
453
|
+
bool maximizable = true;
|
|
454
|
+
|
|
455
|
+
// ── Transparency ──
|
|
456
|
+
bool transparent = false; // Allow per-pixel alpha (requires frameless on some platforms)
|
|
457
|
+
float opacity = 1.0f; // Window-level opacity [0.0–1.0]
|
|
458
|
+
Color background = {255, 255, 255, 255};
|
|
459
|
+
|
|
460
|
+
// ── Behavior ──
|
|
461
|
+
bool always_on_top = false;
|
|
462
|
+
bool skip_taskbar = false; // Don't show in taskbar/dock
|
|
463
|
+
bool modal = false; // Block parent window
|
|
464
|
+
std::string parent_id = ""; // Parent window ID for child/modal
|
|
465
|
+
bool center = true; // Center on screen (overrides x/y if true)
|
|
466
|
+
|
|
467
|
+
// ── Scrolling ──
|
|
468
|
+
bool scrollbars = true;
|
|
469
|
+
|
|
470
|
+
// ── File Drop ──
|
|
471
|
+
bool file_drop = true;
|
|
472
|
+
|
|
473
|
+
// ── Initial State ──
|
|
474
|
+
WindowState initial_state = WindowState::Normal;
|
|
475
|
+
|
|
476
|
+
// ── WebView ──
|
|
477
|
+
WebViewConfig webview;
|
|
478
|
+
|
|
479
|
+
// ── Frameless Window: Custom Hit-Test ──
|
|
480
|
+
// When frameless=true, you must define where the user can drag/resize.
|
|
481
|
+
// The library provides a default 8px resize border + top 32px caption.
|
|
482
|
+
// Override for custom layouts:
|
|
483
|
+
int resize_border_width = 8; // Pixels from edge that trigger resize
|
|
484
|
+
int caption_height = 32; // Top region height that acts as draggable titlebar
|
|
485
|
+
|
|
486
|
+
// For full control, supply a hit-test callback:
|
|
487
|
+
std::function<HitTestRegion(Point)> on_hit_test;
|
|
488
|
+
|
|
489
|
+
// ── Event Callbacks ──
|
|
490
|
+
std::function<void()> on_created;
|
|
491
|
+
std::function<void()> on_shown;
|
|
492
|
+
std::function<void()> on_hidden;
|
|
493
|
+
std::function<void()> on_focused;
|
|
494
|
+
std::function<void()> on_blurred;
|
|
495
|
+
std::function<void(ResizeEvent)> on_resize;
|
|
496
|
+
std::function<void(MoveEvent)> on_move;
|
|
497
|
+
std::function<bool()> on_close_requested; // Return false to cancel
|
|
498
|
+
std::function<void()> on_closed;
|
|
499
|
+
std::function<void(WindowState)> on_state_changed;
|
|
500
|
+
std::function<void(float)> on_scale_changed; // DPI change
|
|
501
|
+
|
|
502
|
+
// ── Input Callbacks ──
|
|
503
|
+
std::function<void(MouseEvent)> on_mouse_down;
|
|
504
|
+
std::function<void(MouseEvent)> on_mouse_up;
|
|
505
|
+
std::function<void(MouseEvent)> on_mouse_move;
|
|
506
|
+
std::function<void(MouseEvent)> on_mouse_scroll;
|
|
507
|
+
std::function<void(MouseEvent)> on_mouse_enter;
|
|
508
|
+
std::function<void(MouseEvent)> on_mouse_leave;
|
|
509
|
+
std::function<void(KeyEvent)> on_key_down;
|
|
510
|
+
std::function<void(KeyEvent)> on_key_up;
|
|
511
|
+
std::function<void(DropEvent)> on_file_drop;
|
|
512
|
+
|
|
513
|
+
// ── Paint Callback ──
|
|
514
|
+
// Called when the window needs repainting. Use with raw pixel buffer
|
|
515
|
+
// or integrate your own renderer (OpenGL, Vulkan, Metal, etc.)
|
|
516
|
+
std::function<void(void* native_handle)> on_paint;
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
520
|
+
// Window — Handle to a created window
|
|
521
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
522
|
+
|
|
523
|
+
class Window {
|
|
524
|
+
public:
|
|
525
|
+
virtual ~Window() = default;
|
|
526
|
+
|
|
527
|
+
// ── Getters ──
|
|
528
|
+
virtual std::string id() const = 0;
|
|
529
|
+
virtual std::string title() const = 0;
|
|
530
|
+
virtual Size size() const = 0;
|
|
531
|
+
virtual Point position() const = 0;
|
|
532
|
+
virtual WindowState state() const = 0;
|
|
533
|
+
virtual bool is_visible() const = 0;
|
|
534
|
+
virtual bool is_focused() const = 0;
|
|
535
|
+
virtual float scale_factor() const = 0;
|
|
536
|
+
virtual void* native_handle() const = 0; // HWND, NSWindow*, X11 Window
|
|
537
|
+
|
|
538
|
+
// ── Setters ──
|
|
539
|
+
virtual void set_title(const std::string& title) = 0;
|
|
540
|
+
virtual void set_size(int w, int h) = 0;
|
|
541
|
+
virtual void set_position(int x, int y) = 0;
|
|
542
|
+
virtual void set_min_size(int w, int h) = 0;
|
|
543
|
+
virtual void set_max_size(int w, int h) = 0;
|
|
544
|
+
virtual void set_resizable(bool v) = 0;
|
|
545
|
+
virtual void set_always_on_top(bool v) = 0;
|
|
546
|
+
virtual void set_opacity(float v) = 0;
|
|
547
|
+
virtual void set_background(Color c) = 0;
|
|
548
|
+
virtual void set_cursor(CursorType c) = 0;
|
|
549
|
+
|
|
550
|
+
// ── Actions ──
|
|
551
|
+
virtual void show() = 0;
|
|
552
|
+
virtual void hide() = 0;
|
|
553
|
+
virtual void close() = 0;
|
|
554
|
+
virtual void focus() = 0;
|
|
555
|
+
virtual void minimize() = 0;
|
|
556
|
+
virtual void maximize() = 0;
|
|
557
|
+
virtual void restore() = 0;
|
|
558
|
+
virtual void fullscreen() = 0;
|
|
559
|
+
virtual void center() = 0;
|
|
560
|
+
virtual void request_repaint() = 0;
|
|
561
|
+
|
|
562
|
+
// ── Drag (for frameless windows) ──
|
|
563
|
+
virtual void start_drag() = 0; // Begin window drag from current mouse pos
|
|
564
|
+
virtual void start_resize(HitTestRegion edge) = 0;
|
|
565
|
+
|
|
566
|
+
virtual WebView* webview() = 0;
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
570
|
+
// Application — The singleton app controller
|
|
571
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
572
|
+
|
|
573
|
+
class Application {
|
|
574
|
+
public:
|
|
575
|
+
virtual ~Application() = default;
|
|
576
|
+
|
|
577
|
+
// ── Create / Access Windows ──
|
|
578
|
+
virtual Window* create_window(const WindowConfig& config) = 0;
|
|
579
|
+
virtual Window* get_window(const std::string& id) = 0;
|
|
580
|
+
virtual std::vector<Window*> all_windows() = 0;
|
|
581
|
+
|
|
582
|
+
// ── App Actions ──
|
|
583
|
+
virtual void run() = 0; // Enter main event loop (blocking)
|
|
584
|
+
virtual void quit() = 0;
|
|
585
|
+
virtual void set_tray(const TrayConfig& config) = 0;
|
|
586
|
+
virtual void remove_tray() = 0;
|
|
587
|
+
|
|
588
|
+
// ── System Info ──
|
|
589
|
+
virtual std::vector<MonitorInfo> monitors() = 0;
|
|
590
|
+
virtual MonitorInfo primary_monitor() = 0;
|
|
591
|
+
|
|
592
|
+
// ── Clipboard ──
|
|
593
|
+
virtual std::string clipboard_text() = 0;
|
|
594
|
+
virtual void set_clipboard_text(const std::string& text) = 0;
|
|
595
|
+
|
|
596
|
+
// ── Inter-Window Messaging ──
|
|
597
|
+
virtual void send_message(const std::string& window_id,
|
|
598
|
+
const std::string& event,
|
|
599
|
+
const std::string& payload = "") = 0;
|
|
600
|
+
|
|
601
|
+
using MessageHandler = std::function<void(const std::string& event,
|
|
602
|
+
const std::string& payload)>;
|
|
603
|
+
virtual void on_message(const std::string& window_id, MessageHandler handler) = 0;
|
|
604
|
+
|
|
605
|
+
// ── Timers ──
|
|
606
|
+
using TimerId = uint64_t;
|
|
607
|
+
virtual TimerId set_timeout(uint32_t ms, std::function<void()> callback) = 0;
|
|
608
|
+
virtual TimerId set_interval(uint32_t ms, std::function<void()> callback) = 0;
|
|
609
|
+
virtual void clear_timer(TimerId id) = 0;
|
|
610
|
+
|
|
611
|
+
// ── Run on Main Thread (thread-safe) ──
|
|
612
|
+
virtual void dispatch(std::function<void()> fn) = 0;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
616
|
+
// Entry Point — The only function you call
|
|
617
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
618
|
+
|
|
619
|
+
/// Creates the application singleton. Call once.
|
|
620
|
+
std::unique_ptr<Application> create_app(const AppConfig& config);
|
|
621
|
+
|
|
622
|
+
// ─── Path Utilities ──────────────────────────────────────────────────────────
|
|
623
|
+
|
|
624
|
+
namespace paths {
|
|
625
|
+
|
|
626
|
+
/// Returns the OS-standard application data directory for the given app name,
|
|
627
|
+
/// creating it if it does not already exist.
|
|
628
|
+
///
|
|
629
|
+
/// Windows : %%APPDATA%%\\<app_name> (C:\Users\...\AppData\Roaming\<app_name>)
|
|
630
|
+
/// macOS : ~/Library/Application Support/<app_name>
|
|
631
|
+
/// Linux : $XDG_DATA_HOME/<app_name> or ~/.local/share/<app_name>
|
|
632
|
+
///
|
|
633
|
+
/// Use this for config files, SQLite databases, and the WebView user data dir.
|
|
634
|
+
std::string app_data_dir(const std::string& app_name);
|
|
635
|
+
|
|
636
|
+
} // namespace paths
|
|
637
|
+
|
|
638
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
639
|
+
// API Helpers — Convenience structs and free functions
|
|
640
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
641
|
+
|
|
642
|
+
namespace api {
|
|
643
|
+
|
|
644
|
+
struct AppInfo {
|
|
645
|
+
std::string name;
|
|
646
|
+
std::string version;
|
|
647
|
+
std::string identifier;
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
struct WindowInfo {
|
|
651
|
+
std::string id;
|
|
652
|
+
std::string title;
|
|
653
|
+
Size size;
|
|
654
|
+
Point position;
|
|
655
|
+
WindowState state;
|
|
656
|
+
bool visible;
|
|
657
|
+
bool focused;
|
|
658
|
+
float scale_factor;
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
inline AppInfo app_info(const AppConfig& config) {
|
|
662
|
+
return AppInfo{config.name, config.version, config.identifier};
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
inline std::vector<MonitorInfo> monitors(Application& app) {
|
|
666
|
+
return app.monitors();
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
inline MonitorInfo primary_monitor(Application& app) {
|
|
670
|
+
return app.primary_monitor();
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
inline std::string clipboard_text(Application& app) {
|
|
674
|
+
return app.clipboard_text();
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
inline void set_clipboard_text(Application& app, const std::string& text) {
|
|
678
|
+
app.set_clipboard_text(text);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
inline WindowInfo window_info(Window& window) {
|
|
682
|
+
return WindowInfo{
|
|
683
|
+
window.id(),
|
|
684
|
+
window.title(),
|
|
685
|
+
window.size(),
|
|
686
|
+
window.position(),
|
|
687
|
+
window.state(),
|
|
688
|
+
window.is_visible(),
|
|
689
|
+
window.is_focused(),
|
|
690
|
+
window.scale_factor(),
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
inline std::vector<WindowInfo> window_infos(Application& app) {
|
|
695
|
+
std::vector<WindowInfo> result;
|
|
696
|
+
for (auto* window : app.all_windows()) {
|
|
697
|
+
if (window) result.push_back(window_info(*window));
|
|
698
|
+
}
|
|
699
|
+
return result;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
} // namespace api
|
|
703
|
+
|
|
704
|
+
} // namespace wpp
|