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.
Files changed (88) hide show
  1. package/bin/windowpp.js +86 -0
  2. package/cmake/embed_assets.py +144 -0
  3. package/framework/CMakeLists.txt +176 -0
  4. package/framework/include/windowpp/windowpp.h +704 -0
  5. package/framework/src/AppData/API/AppData.ts +137 -0
  6. package/framework/src/AppData/appdata_bridge.h +138 -0
  7. package/framework/src/AppData/appdata_manager.cpp +126 -0
  8. package/framework/src/AppData/appdata_manager.h +3 -0
  9. package/framework/src/FileSystem/API/FileSystem.ts +389 -0
  10. package/framework/src/FileSystem/Linux/filesearch.cpp +148 -0
  11. package/framework/src/FileSystem/Linux/readfile.cpp +79 -0
  12. package/framework/src/FileSystem/Linux/savefile.cpp +333 -0
  13. package/framework/src/FileSystem/MacOS/filesearch.cpp +149 -0
  14. package/framework/src/FileSystem/MacOS/readfile.cpp +80 -0
  15. package/framework/src/FileSystem/MacOS/savefile.cpp +264 -0
  16. package/framework/src/FileSystem/Windows/filesearch.cpp +195 -0
  17. package/framework/src/FileSystem/Windows/readfile.cpp +122 -0
  18. package/framework/src/FileSystem/Windows/savefile.cpp +290 -0
  19. package/framework/src/FileSystem/file_index_service.cpp +262 -0
  20. package/framework/src/FileSystem/file_index_service.h +55 -0
  21. package/framework/src/FileSystem/filesystem_bridge.h +243 -0
  22. package/framework/src/FileSystem/filesystem_handler.h +93 -0
  23. package/framework/src/FileSystem/filesystem_json.h +241 -0
  24. package/framework/src/FileSystem/filesystem_search_service.cpp +414 -0
  25. package/framework/src/FileSystem/filesystem_search_service.h +94 -0
  26. package/framework/src/Input/API/Input.ts +161 -0
  27. package/framework/src/Input/Linux/linux_key_utils.h +135 -0
  28. package/framework/src/Input/MacOS/macos_key_utils.h +137 -0
  29. package/framework/src/Input/Windows/win32_key_utils.h +199 -0
  30. package/framework/src/Input/input_bridge.h +192 -0
  31. package/framework/src/Input/input_service.cpp +584 -0
  32. package/framework/src/Input/input_service.h +21 -0
  33. package/framework/src/application.cpp +29 -0
  34. package/framework/src/common/hit_test.cpp +40 -0
  35. package/framework/src/common/image_loader.cpp +24 -0
  36. package/framework/src/common/paths.cpp +75 -0
  37. package/framework/src/filedrop/filedrop.cpp +316 -0
  38. package/framework/src/filedrop/filedrop.css +421 -0
  39. package/framework/src/filedrop/filedrop.hpp +92 -0
  40. package/framework/src/filedrop/filedrop.ts +183 -0
  41. package/framework/src/platform/API/App.ts +156 -0
  42. package/framework/src/platform/API/Window.ts +249 -0
  43. package/framework/src/platform/linux/app_linux.cpp +256 -0
  44. package/framework/src/platform/linux/app_linux.h +64 -0
  45. package/framework/src/platform/linux/linux_helpers.cpp +26 -0
  46. package/framework/src/platform/linux/linux_helpers.h +19 -0
  47. package/framework/src/platform/linux/tray_linux.cpp +21 -0
  48. package/framework/src/platform/linux/tray_linux.h +26 -0
  49. package/framework/src/platform/linux/window_linux.cpp +256 -0
  50. package/framework/src/platform/linux/window_linux.h +70 -0
  51. package/framework/src/platform/macos/app_macos.h +59 -0
  52. package/framework/src/platform/macos/app_macos.mm +223 -0
  53. package/framework/src/platform/macos/macos_helpers.h +21 -0
  54. package/framework/src/platform/macos/tray_macos.h +22 -0
  55. package/framework/src/platform/macos/tray_macos.mm +53 -0
  56. package/framework/src/platform/macos/window_macos.h +74 -0
  57. package/framework/src/platform/macos/window_macos.mm +318 -0
  58. package/framework/src/platform/platform_bridge.h +514 -0
  59. package/framework/src/platform/platform_factory.cpp +33 -0
  60. package/framework/src/platform/platform_factory.h +19 -0
  61. package/framework/src/platform/win32/app_win32.cpp +572 -0
  62. package/framework/src/platform/win32/app_win32.h +83 -0
  63. package/framework/src/platform/win32/tray_win32.cpp +57 -0
  64. package/framework/src/platform/win32/tray_win32.h +30 -0
  65. package/framework/src/platform/win32/win32_helpers.h +61 -0
  66. package/framework/src/platform/win32/window_win32.cpp +267 -0
  67. package/framework/src/platform/win32/window_win32.h +79 -0
  68. package/framework/src/renderer/webgpu.h +128 -0
  69. package/framework/src/renderer/webview/include/WebView2.h +48014 -0
  70. package/framework/src/renderer/webview/include/WebView2EnvironmentOptions.h +342 -0
  71. package/framework/src/renderer/webview/webview.h +13 -0
  72. package/framework/src/renderer/webview/webview_linux.cpp +392 -0
  73. package/framework/src/renderer/webview/webview_macos.mm +388 -0
  74. package/framework/src/renderer/webview/webview_win32.cpp +688 -0
  75. package/framework/src/renderer/webview/x64/WebView2Loader.dll +0 -0
  76. package/framework/src/renderer/webview/x64/WebView2Loader.lib +0 -0
  77. package/framework/src/renderer/webview/x64/WebView2LoaderStatic.lib +0 -0
  78. package/lib/build.js +112 -0
  79. package/lib/create.js +283 -0
  80. package/lib/dev.js +155 -0
  81. package/package.json +24 -0
  82. package/scripts/publish.js +67 -0
  83. package/scripts/sync-framework.js +73 -0
  84. package/templates/solid/CMakeLists.txt +56 -0
  85. package/templates/solid/frontend/package.json +22 -0
  86. package/templates/solid/frontend/vite.config.ts +25 -0
  87. package/templates/solid/main.cpp +72 -0
  88. 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