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,223 @@
1
+ // ============================================================================
2
+ // app_macos.mm — macOS/Cocoa Application implementation
3
+ // ============================================================================
4
+
5
+ #import "app_macos.h"
6
+ #include <dispatch/dispatch.h>
7
+ #include "../../renderer/webview/webview.h"
8
+
9
+ @interface PWAppDelegate : NSObject <NSApplicationDelegate> {
10
+ wpp::MacOSApplication* _app;
11
+ }
12
+ - (instancetype)initWithApp:(wpp::MacOSApplication*)app;
13
+ @end
14
+
15
+ @implementation PWAppDelegate
16
+ - (instancetype)initWithApp:(wpp::MacOSApplication*)app {
17
+ self = [super init];
18
+ _app = app;
19
+ return self;
20
+ }
21
+ - (void)applicationDidFinishLaunching:(NSNotification*)notification {
22
+ if (_app->config().on_ready) {
23
+ _app->config().on_ready();
24
+ }
25
+ }
26
+ - (void)applicationWillTerminate:(NSNotification*)notification {
27
+ if (_app->config().on_quit) {
28
+ _app->config().on_quit();
29
+ }
30
+ }
31
+ - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender {
32
+ return _app->config().quit_on_last_close;
33
+ }
34
+ @end
35
+
36
+ namespace wpp {
37
+
38
+ MacOSApplication::MacOSApplication(const AppConfig& config) : config_(config) {
39
+ app_ = [NSApplication sharedApplication];
40
+ delegate_ = [[PWAppDelegate alloc] initWithApp:this];
41
+ app_.delegate = delegate_;
42
+
43
+ [app_ setActivationPolicy:NSApplicationActivationPolicyRegular];
44
+ [app_ activateIgnoringOtherApps:YES];
45
+
46
+ if (config_.tray_enabled) {
47
+ set_tray(config_.tray);
48
+ }
49
+ }
50
+
51
+ MacOSApplication::~MacOSApplication() {
52
+ app_.delegate = nil;
53
+ }
54
+
55
+ Window* MacOSApplication::create_window(const WindowConfig& config) {
56
+ auto id = config.id.empty() ? "main" : config.id;
57
+
58
+ NSWindow* window = create_macos_native_window(config);
59
+
60
+ if (config.frameless) {
61
+ window.opaque = NO;
62
+ window.backgroundColor = [NSColor clearColor];
63
+ window.hasShadow = YES;
64
+ }
65
+
66
+ if (!config.title.empty()) {
67
+ window.title = macos::to_ns(config.title);
68
+ }
69
+
70
+ if (config.always_on_top) {
71
+ window.level = NSWindowLevel(NSIntegerMax);
72
+ }
73
+
74
+ window.minSize = NSMakeSize(config.min_width > 0 ? config.min_width : 0,
75
+ config.min_height > 0 ? config.min_height : 0);
76
+ window.maxSize = NSMakeSize(config.max_width > 0 ? config.max_width : 10000,
77
+ config.max_height > 0 ? config.max_height : 10000);
78
+
79
+ auto window_ptr = std::make_unique<MacOSWindow>(config, window);
80
+
81
+ if (config.webview.enabled) {
82
+ auto webview_config = config.webview;
83
+ webview_config.scrollbars = config.scrollbars;
84
+ window_ptr->set_webview(create_webview(webview_config, (__bridge void*)window));
85
+ if (auto* webview = window_ptr->webview()) {
86
+ webview->set_drag_drop_enabled(config.file_drop);
87
+ }
88
+ }
89
+
90
+ auto* ptr = window_ptr.get();
91
+ windows_[id] = std::move(window_ptr);
92
+
93
+ if (config.initial_state != WindowState::Hidden) {
94
+ [window makeKeyAndOrderFront:nil];
95
+ }
96
+
97
+ if (config.on_created) {
98
+ config.on_created();
99
+ }
100
+
101
+ return ptr;
102
+ }
103
+
104
+ Window* MacOSApplication::get_window(const std::string& id) {
105
+ auto it = windows_.find(id);
106
+ return it != windows_.end() ? it->second.get() : nullptr;
107
+ }
108
+
109
+ std::vector<Window*> MacOSApplication::all_windows() {
110
+ std::vector<Window*> result;
111
+ for (auto& [id, win] : windows_) {
112
+ result.push_back(win.get());
113
+ }
114
+ return result;
115
+ }
116
+
117
+ void MacOSApplication::run() {
118
+ [app_ run];
119
+ }
120
+
121
+ void MacOSApplication::quit() {
122
+ [app_ terminate:nil];
123
+ }
124
+
125
+ void MacOSApplication::set_tray(const TrayConfig& config) {
126
+ tray_ = std::make_unique<MacOSTray>(config);
127
+ }
128
+
129
+ void MacOSApplication::remove_tray() {
130
+ tray_.reset();
131
+ }
132
+
133
+ std::vector<MonitorInfo> MacOSApplication::monitors() {
134
+ std::vector<MonitorInfo> result;
135
+ for (NSScreen* screen in [NSScreen screens]) {
136
+ MonitorInfo mi;
137
+ mi.name = [[screen localizedName] UTF8String];
138
+ mi.bounds = {
139
+ (int)screen.frame.origin.x,
140
+ (int)screen.frame.origin.y,
141
+ (int)screen.frame.size.width,
142
+ (int)screen.frame.size.height
143
+ };
144
+ mi.work_area = {
145
+ (int)screen.visibleFrame.origin.x,
146
+ (int)screen.visibleFrame.origin.y,
147
+ (int)screen.visibleFrame.size.width,
148
+ (int)screen.visibleFrame.size.height
149
+ };
150
+ mi.scale_factor = screen.backingScaleFactor;
151
+ mi.is_primary = (screen == [NSScreen primaryScreen]);
152
+ result.push_back(mi);
153
+ }
154
+ return result;
155
+ }
156
+
157
+ MonitorInfo MacOSApplication::primary_monitor() {
158
+ MonitorInfo mi;
159
+ NSScreen* screen = [NSScreen primaryScreen];
160
+ mi.name = [[screen localizedName] UTF8String];
161
+ mi.bounds = {
162
+ (int)screen.frame.origin.x,
163
+ (int)screen.frame.origin.y,
164
+ (int)screen.frame.size.width,
165
+ (int)screen.frame.size.height
166
+ };
167
+ mi.work_area = {
168
+ (int)screen.visibleFrame.origin.x,
169
+ (int)screen.visibleFrame.origin.y,
170
+ (int)screen.visibleFrame.size.width,
171
+ (int)screen.visibleFrame.size.height
172
+ };
173
+ mi.scale_factor = screen.backingScaleFactor;
174
+ mi.is_primary = YES;
175
+ return mi;
176
+ }
177
+
178
+ std::string MacOSApplication::clipboard_text() {
179
+ return [[NSPasteboard generalPasteboard].string UTF8String] ?: "";
180
+ }
181
+
182
+ void MacOSApplication::set_clipboard_text(const std::string& text) {
183
+ [[NSPasteboard generalPasteboard] clearContents];
184
+ [[NSPasteboard generalPasteboard] setString:macos::to_ns(text) forType:NSPasteboardTypeString];
185
+ }
186
+
187
+ void MacOSApplication::send_message(const std::string& window_id,
188
+ const std::string& event,
189
+ const std::string& payload) {
190
+ auto it = message_handlers_.find(window_id);
191
+ if (it != message_handlers_.end()) {
192
+ for (auto& handler : it->second) {
193
+ handler(event, payload);
194
+ }
195
+ }
196
+ }
197
+
198
+ void MacOSApplication::on_message(const std::string& window_id, MessageHandler handler) {
199
+ message_handlers_[window_id].push_back(handler);
200
+ }
201
+
202
+ Application::TimerId MacOSApplication::set_timeout(uint32_t ms, std::function<void()> callback) {
203
+ return 0;
204
+ }
205
+
206
+ Application::TimerId MacOSApplication::set_interval(uint32_t ms, std::function<void()> callback) {
207
+ return 0;
208
+ }
209
+
210
+ void MacOSApplication::clear_timer(TimerId id) {
211
+ }
212
+
213
+ void MacOSApplication::dispatch(std::function<void()> fn) {
214
+ auto* callback = new std::function<void()>(std::move(fn));
215
+ dispatch_async(dispatch_get_main_queue(), ^{
216
+ std::unique_ptr<std::function<void()>> callback_ptr(callback);
217
+ if (*callback_ptr) {
218
+ (*callback_ptr)();
219
+ }
220
+ });
221
+ }
222
+
223
+ } // namespace wpp
@@ -0,0 +1,21 @@
1
+ // ============================================================================
2
+ // macos_helpers.h — macOS/Cocoa helper utilities
3
+ // ============================================================================
4
+
5
+ #pragma once
6
+
7
+ #import <Cocoa/Cocoa.h>
8
+
9
+ namespace wpp {
10
+ namespace macos {
11
+
12
+ inline NSString* to_ns(const std::string& str) {
13
+ return [NSString stringWithUTF8String:str.c_str()];
14
+ }
15
+
16
+ inline std::string from_ns(NSString* str) {
17
+ return str ? [str UTF8String] : "";
18
+ }
19
+
20
+ } // namespace macos
21
+ } // namespace wpp
@@ -0,0 +1,22 @@
1
+ // ============================================================================
2
+ // tray_macos.h — macOS System Tray implementation
3
+ // ============================================================================
4
+
5
+ #pragma once
6
+
7
+ #import <Cocoa/Cocoa.h>
8
+ #include "windowpp.h"
9
+
10
+ namespace wpp {
11
+
12
+ class MacOSTray {
13
+ public:
14
+ MacOSTray(const TrayConfig& config);
15
+ ~MacOSTray();
16
+
17
+ private:
18
+ TrayConfig config_;
19
+ NSStatusItem* item_;
20
+ };
21
+
22
+ } // namespace wpp
@@ -0,0 +1,53 @@
1
+ // ============================================================================
2
+ // tray_macos.mm — macOS System Tray implementation
3
+ // ============================================================================
4
+
5
+ #import "tray_macos.h"
6
+ #include "macos_helpers.h"
7
+
8
+ @interface PWTrayMenuDelegate : NSObject <NSMenuDelegate> {
9
+ wpp::TrayConfig _config;
10
+ }
11
+ - (instancetype)initWithConfig:(wpp::TrayConfig)config;
12
+ @end
13
+
14
+ @implementation PWTrayMenuDelegate
15
+ - (instancetype)initWithConfig:(wpp::TrayConfig)config {
16
+ self = [super init];
17
+ _config = config;
18
+ return self;
19
+ }
20
+ @end
21
+
22
+ namespace wpp {
23
+
24
+ MacOSTray::MacOSTray(const TrayConfig& config) : config_(config) {
25
+ item_ = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
26
+
27
+ if (!config.icon_path.empty()) {
28
+ item_.button.image = [NSImage imageNamed:macos::to_ns(config.icon_path)];
29
+ } else {
30
+ item_.button.title = @"PW";
31
+ }
32
+
33
+ NSMenu* menu = [[NSMenu alloc] init];
34
+ for (size_t i = 0; i < config.menu.size(); ++i) {
35
+ const auto& menuItem = config.menu[i];
36
+ if (menuItem.is_separator) {
37
+ [menu addItem:[NSMenuItem separatorItem]];
38
+ } else {
39
+ NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:macos::to_ns(menuItem.label)
40
+ action:nil
41
+ keyEquivalent:@""];
42
+ item.enabled = menuItem.enabled;
43
+ [menu addItem:item];
44
+ }
45
+ }
46
+ item_.menu = menu;
47
+ }
48
+
49
+ MacOSTray::~MacOSTray() {
50
+ [[NSStatusBar systemStatusBar] removeStatusItem:item_];
51
+ }
52
+
53
+ } // namespace wpp
@@ -0,0 +1,74 @@
1
+ // ============================================================================
2
+ // window_macos.h — macOS/Cocoa Window implementation
3
+ // ============================================================================
4
+
5
+ #pragma once
6
+
7
+ #import <Cocoa/Cocoa.h>
8
+ #include <map>
9
+ #include <functional>
10
+ #include <memory>
11
+ #include "macos_helpers.h"
12
+ #include "windowpp.h"
13
+
14
+ @class PWWindowDelegate;
15
+
16
+ namespace wpp {
17
+
18
+ class MacOSWindow : public Window {
19
+ public:
20
+ MacOSWindow(const WindowConfig& config, NSWindow* window);
21
+ ~MacOSWindow() override;
22
+
23
+ std::string id() const override { return config_.id; }
24
+ std::string title() const override;
25
+ Size size() const override;
26
+ Point position() const override;
27
+ WindowState state() const override;
28
+ bool is_visible() const override;
29
+ bool is_focused() const override;
30
+ float scale_factor() const override;
31
+ void* native_handle() const override { return (__bridge void*)window_; }
32
+
33
+ void set_title(const std::string& title) override;
34
+ void set_size(int w, int h) override;
35
+ void set_position(int x, int y) override;
36
+ void set_min_size(int w, int h) override;
37
+ void set_max_size(int w, int h) override;
38
+ void set_resizable(bool v) override;
39
+ void set_always_on_top(bool v) override;
40
+ void set_opacity(float v) override;
41
+ void set_background(Color c) override;
42
+ void set_cursor(CursorType c) override;
43
+
44
+ void show() override;
45
+ void hide() override;
46
+ void close() override;
47
+ void focus() override;
48
+ void minimize() override;
49
+ void maximize() override;
50
+ void restore() override;
51
+ void fullscreen() override;
52
+ void center() override;
53
+ void request_repaint() override;
54
+ void start_drag() override;
55
+ void start_resize(HitTestRegion edge) override;
56
+
57
+ WebView* webview() override { return webview_.get(); }
58
+ void set_webview(std::unique_ptr<WebView> wv) { webview_ = std::move(wv); }
59
+
60
+ NSWindow* window() const { return window_; }
61
+ const WindowConfig& config() const { return config_; }
62
+
63
+ HitTestRegion hit_test(Point cursor);
64
+
65
+ private:
66
+ WindowConfig config_;
67
+ NSWindow* window_;
68
+ PWWindowDelegate* delegate_;
69
+ std::unique_ptr<WebView> webview_;
70
+ };
71
+
72
+ NSWindow* create_macos_native_window(const WindowConfig& config);
73
+
74
+ } // namespace wpp
@@ -0,0 +1,318 @@
1
+ // ============================================================================
2
+ // window_macos.mm — macOS/Cocoa Window implementation
3
+ // ============================================================================
4
+
5
+ #import "window_macos.h"
6
+ #include "../../Input/input_service.h"
7
+ #include "../../Input/MacOS/macos_key_utils.h"
8
+ #include <algorithm>
9
+
10
+ @interface PWInputWindow : NSWindow {
11
+ wpp::MacOSWindow* _plusWindow;
12
+ }
13
+ - (void)setWindowPPRef:(wpp::MacOSWindow*)window;
14
+ @end
15
+
16
+ @implementation PWInputWindow
17
+ - (void)setWindowPPRef:(wpp::MacOSWindow*)window {
18
+ _plusWindow = window;
19
+ }
20
+
21
+ - (void)sendEvent:(NSEvent*)event {
22
+ if (_plusWindow) {
23
+ switch (event.type) {
24
+ case NSEventTypeKeyDown: {
25
+ auto translated = wpp::input::macos::make_key_event(event, _plusWindow->id(), wpp::input::KeyEventType::KeyDown);
26
+ wpp::input::detail::emit_key_event(translated);
27
+ if (_plusWindow->config().on_key_down) {
28
+ _plusWindow->config().on_key_down(translated);
29
+ }
30
+ break;
31
+ }
32
+ case NSEventTypeKeyUp: {
33
+ auto translated = wpp::input::macos::make_key_event(event, _plusWindow->id(), wpp::input::KeyEventType::KeyUp);
34
+ wpp::input::detail::emit_key_event(translated);
35
+ if (_plusWindow->config().on_key_up) {
36
+ _plusWindow->config().on_key_up(translated);
37
+ }
38
+ break;
39
+ }
40
+ case NSEventTypeFlagsChanged: {
41
+ auto translated = wpp::input::macos::make_flags_changed_event(event, _plusWindow->id());
42
+ wpp::input::detail::emit_key_event(translated);
43
+ if (translated.type == wpp::input::KeyEventType::KeyDown) {
44
+ if (_plusWindow->config().on_key_down) {
45
+ _plusWindow->config().on_key_down(translated);
46
+ }
47
+ } else if (_plusWindow->config().on_key_up) {
48
+ _plusWindow->config().on_key_up(translated);
49
+ }
50
+ break;
51
+ }
52
+ default:
53
+ break;
54
+ }
55
+ }
56
+ [super sendEvent:event];
57
+ }
58
+ @end
59
+
60
+ @interface PWWindowDelegate : NSObject <NSWindowDelegate> {
61
+ wpp::MacOSWindow* _window;
62
+ }
63
+ - (instancetype)initWithWindow:(wpp::MacOSWindow*)window;
64
+ @end
65
+
66
+ @implementation PWWindowDelegate
67
+ - (instancetype)initWithWindow:(wpp::MacOSWindow*)window {
68
+ self = [super init];
69
+ _window = window;
70
+ return self;
71
+ }
72
+ - (void)windowDidResize:(NSNotification*)notification {
73
+ if (_window->config().on_resize) {
74
+ NSSize size = _window->window().frame.size;
75
+ _window->config().on_resize({{0, 0}, {(int)size.width, (int)size.height}});
76
+ }
77
+ }
78
+ - (void)windowDidMove:(NSNotification*)notification {
79
+ if (_window->config().on_move) {
80
+ NSPoint pos = _window->window().frame.origin;
81
+ _window->config().on_move({{(int)pos.x, (int)pos.y}, {(int)pos.x, (int)pos.y}});
82
+ }
83
+ }
84
+ - (void)windowWillClose:(NSNotification*)notification {
85
+ if (_window->config().on_close_requested && !_window->config().on_close_requested()) {
86
+ return;
87
+ }
88
+ if (_window->config().on_closed) {
89
+ _window->config().on_closed();
90
+ }
91
+ }
92
+ @end
93
+
94
+ namespace wpp {
95
+
96
+ NSWindow* create_macos_native_window(const WindowConfig& config) {
97
+ NSRect frame = NSMakeRect(
98
+ config.x >= 0 ? config.x : 100,
99
+ config.y >= 0 ? config.y : 100,
100
+ config.width,
101
+ config.height
102
+ );
103
+
104
+ NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
105
+ if (config.resizable) styleMask |= NSWindowStyleMaskResizable;
106
+ if (config.minimizable) styleMask |= NSWindowStyleMaskMiniaturizable;
107
+
108
+ if (config.frameless) {
109
+ styleMask = NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable;
110
+ }
111
+
112
+ PWInputWindow* window = [[PWInputWindow alloc] initWithContentRect:frame
113
+ styleMask:styleMask
114
+ backing:NSBackingStoreBuffered
115
+ defer:NO];
116
+
117
+ if (config.frameless) {
118
+ window.opaque = NO;
119
+ window.backgroundColor = [NSColor clearColor];
120
+ window.hasShadow = YES;
121
+ }
122
+
123
+ return window;
124
+ }
125
+
126
+ MacOSWindow::MacOSWindow(const WindowConfig& config, NSWindow* window)
127
+ : config_(config), window_(window) {
128
+ delegate_ = [[PWWindowDelegate alloc] initWithWindow:this];
129
+ window_.delegate = delegate_;
130
+ if ([window_ respondsToSelector:@selector(setWindowPPRef:)]) {
131
+ [(PWInputWindow*)window_ setWindowPPRef:this];
132
+ }
133
+ }
134
+
135
+ MacOSWindow::~MacOSWindow() {
136
+ [window_ close];
137
+ }
138
+
139
+ std::string MacOSWindow::title() const {
140
+ return macos::from_ns(window_.title);
141
+ }
142
+
143
+ Size MacOSWindow::size() const {
144
+ NSRect frame = window_.frame;
145
+ return {(int)frame.size.width, (int)frame.size.height};
146
+ }
147
+
148
+ Point MacOSWindow::position() const {
149
+ NSRect frame = window_.frame;
150
+ return {(int)frame.origin.x, (int)frame.origin.y};
151
+ }
152
+
153
+ WindowState MacOSWindow::state() const {
154
+ if (!window_.isVisible) return WindowState::Hidden;
155
+ if (window_.isZoomed) return WindowState::Maximized;
156
+ if (window_.isMiniaturized) return WindowState::Minimized;
157
+ return WindowState::Normal;
158
+ }
159
+
160
+ bool MacOSWindow::is_visible() const {
161
+ return window_.isVisible;
162
+ }
163
+
164
+ bool MacOSWindow::is_focused() const {
165
+ return [NSApp keyWindow] == window_;
166
+ }
167
+
168
+ float MacOSWindow::scale_factor() const {
169
+ return window_.backingScaleFactor;
170
+ }
171
+
172
+ void MacOSWindow::set_title(const std::string& title) {
173
+ window_.title = macos::to_ns(title);
174
+ }
175
+
176
+ void MacOSWindow::set_size(int w, int h) {
177
+ NSRect frame = window_.frame;
178
+ frame.size.width = w;
179
+ frame.size.height = h;
180
+ [window_ setFrame:frame display:YES];
181
+ }
182
+
183
+ void MacOSWindow::set_position(int x, int y) {
184
+ NSRect frame = window_.frame;
185
+ frame.origin.x = x;
186
+ frame.origin.y = y;
187
+ [window_ setFrame:frame display:YES];
188
+ }
189
+
190
+ void MacOSWindow::set_min_size(int w, int h) {
191
+ config_.min_width = w;
192
+ config_.min_height = h;
193
+ window_.minSize = NSMakeSize(w, h);
194
+ }
195
+
196
+ void MacOSWindow::set_max_size(int w, int h) {
197
+ config_.max_width = w;
198
+ config_.max_height = h;
199
+ window_.maxSize = NSMakeSize(w, h);
200
+ }
201
+
202
+ void MacOSWindow::set_resizable(bool v) {
203
+ config_.resizable = v;
204
+ if (v) {
205
+ window_.styleMask |= NSWindowStyleMaskResizable;
206
+ } else {
207
+ window_.styleMask &= ~NSWindowStyleMaskResizable;
208
+ }
209
+ }
210
+
211
+ void MacOSWindow::set_always_on_top(bool v) {
212
+ window_.level = v ? NSWindowLevel(NSIntegerMax) : NSNormalWindowLevel;
213
+ }
214
+
215
+ void MacOSWindow::set_opacity(float v) {
216
+ window_.alphaValue = v;
217
+ }
218
+
219
+ void MacOSWindow::set_background(Color c) {
220
+ config_.background = c;
221
+ window_.backgroundColor = [NSColor colorWithRed:c.r/255.0 green:c.g/255.0 blue:c.b/255.0 alpha:c.a/255.0];
222
+ }
223
+
224
+ void MacOSWindow::set_cursor(CursorType c) {
225
+ NSCursor* cursor;
226
+ switch (c) {
227
+ case CursorType::Arrow: cursor = [NSCursor arrowCursor]; break;
228
+ case CursorType::Hand: cursor = [NSCursor pointingHandCursor]; break;
229
+ case CursorType::IBeam: cursor = [NSCursor IBeamCursor]; break;
230
+ case CursorType::Crosshair: cursor = [NSCursor crosshairCursor]; break;
231
+ case CursorType::ResizeNS: cursor = [NSCursor resizeUpDownCursor]; break;
232
+ case CursorType::ResizeEW: cursor = [NSCursor resizeLeftRightCursor]; break;
233
+ default: cursor = [NSCursor arrowCursor]; break;
234
+ }
235
+ [cursor set];
236
+ }
237
+
238
+ void MacOSWindow::show() {
239
+ [window_ makeKeyAndOrderFront:nil];
240
+ if (config_.on_shown) config_.on_shown();
241
+ }
242
+
243
+ void MacOSWindow::hide() {
244
+ [window_ orderOut:nil];
245
+ if (config_.on_hidden) config_.on_hidden();
246
+ }
247
+
248
+ void MacOSWindow::close() {
249
+ if (config_.on_close_requested && !config_.on_close_requested()) {
250
+ return;
251
+ }
252
+ [window_ close];
253
+ if (config_.on_closed) config_.on_closed();
254
+ }
255
+
256
+ void MacOSWindow::focus() {
257
+ [window_ makeKeyWindow];
258
+ }
259
+
260
+ void MacOSWindow::minimize() {
261
+ [window_ miniaturize:nil];
262
+ }
263
+
264
+ void MacOSWindow::maximize() {
265
+ [window_ zoom:nil];
266
+ }
267
+
268
+ void MacOSWindow::restore() {
269
+ [window_ deminiaturize:nil];
270
+ }
271
+
272
+ void MacOSWindow::fullscreen() {
273
+ if (window_.styleMask & NSWindowStyleMaskFullScreen) {
274
+ [window_ toggleFullScreen:nil];
275
+ }
276
+ }
277
+
278
+ void MacOSWindow::center() {
279
+ [window_ center];
280
+ }
281
+
282
+ void MacOSWindow::request_repaint() {
283
+ [window_ display];
284
+ }
285
+
286
+ void MacOSWindow::start_drag() {
287
+ [window_ performWindowDragWithEvent:nil];
288
+ }
289
+
290
+ void MacOSWindow::start_resize(HitTestRegion edge) {
291
+ NSSize minSize = window_.minSize;
292
+ NSSize maxSize = window_.maxSize;
293
+
294
+ NSPoint corner = NSZeroPoint;
295
+ switch (edge) {
296
+ case HitTestRegion::ResizeTopLeft: corner = NSMakePoint(0, 1); break;
297
+ case HitTestRegion::ResizeTopRight: corner = NSMakePoint(1, 1); break;
298
+ case HitTestRegion::ResizeBottomLeft: corner = NSMakePoint(0, 0); break;
299
+ case HitTestRegion::ResizeBottomRight: corner = NSMakePoint(1, 0); break;
300
+ case HitTestRegion::ResizeTop: corner = NSMakePoint(0.5, 1); break;
301
+ case HitTestRegion::ResizeBottom: corner = NSMakePoint(0.5, 0); break;
302
+ case HitTestRegion::ResizeLeft: corner = NSMakePoint(0, 0.5); break;
303
+ case HitTestRegion::ResizeRight: corner = NSMakePoint(1, 0.5); break;
304
+ default: return;
305
+ }
306
+ }
307
+
308
+ HitTestRegion MacOSWindow::hit_test(Point cursor) {
309
+ if (config_.on_hit_test) {
310
+ return config_.on_hit_test(cursor);
311
+ }
312
+ return default_hit_test(cursor, size(),
313
+ config_.resize_border_width,
314
+ config_.caption_height,
315
+ config_.resizable);
316
+ }
317
+
318
+ } // namespace wpp