Skip to content

Commit d57bfcc

Browse files
committed
Refactor docs to emphasize separate platform files
Updated documentation to recommend separating platform-specific code into dedicated implementation files per platform (Windows, macOS, Linux) rather than using preprocessor guards. Examples and best practices now show platform-specific code in their respective directories, improving clarity and maintainability.
1 parent a495a69 commit d57bfcc

File tree

2 files changed

+182
-149
lines changed

2 files changed

+182
-149
lines changed

.cursor/rules/native-object-provider.mdc

Lines changed: 169 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void* Window::GetNativeObjectInternal() const {
160160

161161
### Cross-Platform Usage
162162

163-
Users can access native objects when they need platform-specific functionality:
163+
Users can access native objects when they need platform-specific functionality. Since platform-specific implementations are separated into `/platform/{windows|macos|linux}` directories, users should cast the native handle to the appropriate platform-specific type:
164164

165165
```cpp
166166
#include <nativeapi.h>
@@ -173,41 +173,33 @@ auto window = manager.Create(options);
173173
// Get native handle
174174
void* native = window->GetNativeObject();
175175

176-
// Cast to platform-specific type based on compile-time platform
177-
#ifdef _WIN32
178-
HWND hwnd = static_cast<HWND>(native);
179-
// Use Win32 API with hwnd
180-
SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
181-
182-
#elif defined(__APPLE__)
183-
NSWindow* nswindow = static_cast<NSWindow*>(native);
184-
// Use Cocoa API with nswindow
185-
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
186-
187-
#elif defined(__linux__)
188-
GtkWidget* gtkwindow = static_cast<GtkWidget*>(native);
189-
// Use GTK API with gtkwindow
190-
gtk_window_set_keep_above(GTK_WINDOW(gtkwindow), TRUE);
191-
#endif
176+
// Cast to platform-specific type
177+
// Windows: HWND
178+
// macOS: NSWindow*
179+
// Linux: GtkWidget* (GtkWindow)
192180
```
193181

194-
### Runtime Platform Detection
195-
196-
For libraries that need to work across platforms:
182+
### Platform-Specific Usage Examples
197183

184+
#### Windows Implementation
198185
```cpp
199-
void* native = window->GetNativeObject();
186+
// In Windows-specific code
187+
HWND hwnd = static_cast<HWND>(window->GetNativeObject());
188+
SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
189+
```
200190

201-
#if defined(_WIN32)
202-
HWND hwnd = static_cast<HWND>(native);
203-
// Windows-specific code
204-
#elif defined(__APPLE__)
205-
NSWindow* nswindow = static_cast<NSWindow*>(native);
206-
// macOS-specific code
207-
#elif defined(__linux__)
208-
GtkWidget* gtkwindow = static_cast<GtkWidget*>(native);
209-
// Linux-specific code
210-
#endif
191+
#### macOS Implementation
192+
```objc
193+
// In macOS-specific code
194+
NSWindow* nswindow = static_cast<NSWindow*>(window->GetNativeObject());
195+
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
196+
```
197+
198+
#### Linux Implementation
199+
```cpp
200+
// In Linux-specific code
201+
GtkWidget* gtkwindow = static_cast<GtkWidget*>(window->GetNativeObject());
202+
gtk_window_set_keep_above(GTK_WINDOW(gtkwindow), TRUE);
211203
```
212204

213205
## Classes Using NativeObjectProvider
@@ -229,50 +221,75 @@ The following classes inherit from NativeObjectProvider:
229221
```cpp
230222
// User wants to make window transparent (not in cross-platform API)
231223
auto window = manager.Create(options);
224+
void* native = window->GetNativeObject();
232225

233-
#ifdef _WIN32
234-
HWND hwnd = static_cast<HWND>(window->GetNativeObject());
235-
236-
// Enable transparency using Win32 API
237-
SetWindowLongPtr(hwnd, GWL_EXSTYLE,
238-
GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
239-
SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 128, LWA_ALPHA);
240-
241-
#elif defined(__APPLE__)
242-
NSWindow* nswindow = static_cast<NSWindow*>(window->GetNativeObject());
243-
244-
// Enable transparency using Cocoa API
245-
[nswindow setOpaque:NO];
246-
[nswindow setBackgroundColor:[NSColor colorWithRed:0 green:0 blue:0 alpha:0.5]];
247-
248-
#elif defined(__linux__)
249-
GtkWidget* gtkwindow = static_cast<GtkWidget*>(window->GetNativeObject());
250-
251-
// Enable transparency using GTK API
252-
gtk_widget_set_opacity(gtkwindow, 0.5);
253-
#endif
226+
// Platform-specific implementations would be in separate files:
227+
// - Windows: platform/windows/window_windows.cpp
228+
// - macOS: platform/macos/window_macos.mm
229+
// - Linux: platform/linux/window_linux.cpp
230+
```
231+
232+
#### Windows Implementation
233+
```cpp
234+
// In platform/windows/window_windows.cpp
235+
HWND hwnd = static_cast<HWND>(native);
236+
237+
// Enable transparency using Win32 API
238+
SetWindowLongPtr(hwnd, GWL_EXSTYLE,
239+
GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
240+
SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 128, LWA_ALPHA);
241+
```
242+
243+
#### macOS Implementation
244+
```objc
245+
// In platform/macos/window_macos.mm
246+
NSWindow* nswindow = static_cast<NSWindow*>(native);
247+
248+
// Enable transparency using Cocoa API
249+
[nswindow setOpaque:NO];
250+
[nswindow setBackgroundColor:[NSColor colorWithRed:0 green:0 blue:0 alpha:0.5]];
251+
```
252+
253+
#### Linux Implementation
254+
```cpp
255+
// In platform/linux/window_linux.cpp
256+
GtkWidget* gtkwindow = static_cast<GtkWidget*>(native);
257+
258+
// Enable transparency using GTK API
259+
gtk_widget_set_opacity(gtkwindow, 0.5);
254260
```
255261

256262
### Use Case 2: Integrating with Third-Party Libraries
257263

258264
```cpp
259265
// Embedding a web view that expects native window handle
260266
auto window = manager.Create(options);
267+
void* native = window->GetNativeObject();
261268

262-
#ifdef _WIN32
263-
HWND hwnd = static_cast<HWND>(window->GetNativeObject());
264-
WebView2::Create(hwnd, ...);
265-
266-
#elif defined(__APPLE__)
267-
NSWindow* nswindow = static_cast<NSWindow*>(window->GetNativeObject());
268-
WKWebView* webview = [[WKWebView alloc] initWithFrame:[nswindow contentView].bounds];
269-
[[nswindow contentView] addSubview:webview];
270-
271-
#elif defined(__linux__)
272-
GtkWidget* gtkwindow = static_cast<GtkWidget*>(window->GetNativeObject());
273-
GtkWidget* webview = webkit_web_view_new();
274-
gtk_container_add(GTK_CONTAINER(gtkwindow), webview);
275-
#endif
269+
// Platform-specific implementations would be in separate files
270+
```
271+
272+
#### Windows Implementation
273+
```cpp
274+
// In platform/windows/window_windows.cpp
275+
HWND hwnd = static_cast<HWND>(native);
276+
WebView2::Create(hwnd, ...);
277+
```
278+
279+
#### macOS Implementation
280+
```objc
281+
// In platform/macos/window_macos.mm
282+
NSWindow* nswindow = static_cast<NSWindow*>(native);
283+
WKWebView* webview = [[WKWebView alloc] initWithFrame:[nswindow contentView].bounds];
284+
[[nswindow contentView] addSubview:webview];
285+
```
286+
287+
#### Linux Implementation
288+
```cpp
289+
// In platform/linux/window_linux.cpp
290+
GtkWidget* gtkwindow = static_cast<GtkWidget*>(native);
291+
GtkWidget* webview = webkit_web_view_new();
292+
gtk_container_add(GTK_CONTAINER(gtkwindow), webview);
276293
```
277294

278295
### Use Case 3: Platform-Specific Menu Customization
@@ -282,40 +299,51 @@ auto menu = std::make_shared<Menu>();
282299
auto item = std::make_shared<MenuItem>("File");
283300
menu->AddItem(item);
284301

285-
#ifdef __APPLE__
286-
// Add macOS-specific menu behavior
287-
NSMenu* nsmenu = static_cast<NSMenu*>(menu->GetNativeObject());
288-
[nsmenu setAutoenablesItems:NO];
289-
290-
NSMenuItem* nsitem = static_cast<NSMenuItem*>(item->GetNativeObject());
291-
[nsitem setTarget:customTarget];
292-
[nsitem setAction:@selector(customAction:)];
293-
#endif
302+
// Platform-specific implementations would be in separate files
303+
```
304+
305+
#### macOS Implementation
306+
```objc
307+
// In platform/macos/menu_macos.mm
308+
NSMenu* nsmenu = static_cast<NSMenu*>(menu->GetNativeObject());
309+
[nsmenu setAutoenablesItems:NO];
310+
311+
NSMenuItem* nsitem = static_cast<NSMenuItem*>(item->GetNativeObject());
312+
[nsitem setTarget:customTarget];
313+
[nsitem setAction:@selector(customAction:)];
294314
```
295315

296316
### Use Case 4: Advanced Display Configuration
297317

298318
```cpp
299319
auto& display_manager = DisplayManager::GetInstance();
300320
auto primary = display_manager.GetPrimary();
321+
void* native = primary.GetNativeObject();
301322

302-
#ifdef _WIN32
303-
HMONITOR hmonitor = static_cast<HMONITOR>(primary.GetNativeObject());
304-
305-
MONITORINFOEX mi = {};
306-
mi.cbSize = sizeof(MONITORINFOEX);
307-
GetMonitorInfo(hmonitor, &mi);
308-
309-
// Access device name for advanced configuration
310-
std::wcout << L"Device: " << mi.szDevice << std::endl;
311-
312-
#elif defined(__APPLE__)
313-
NSScreen* screen = static_cast<NSScreen*>(primary.GetNativeObject());
314-
315-
// Access color space information
316-
NSColorSpace* colorSpace = [screen colorSpace];
317-
std::cout << "Color space: " << [[colorSpace localizedName] UTF8String] << std::endl;
318-
#endif
323+
// Platform-specific implementations would be in separate files
324+
```
325+
326+
#### Windows Implementation
327+
```cpp
328+
// In platform/windows/display_windows.cpp
329+
HMONITOR hmonitor = static_cast<HMONITOR>(native);
330+
331+
MONITORINFOEX mi = {};
332+
mi.cbSize = sizeof(MONITORINFOEX);
333+
GetMonitorInfo(hmonitor, &mi);
334+
335+
// Access device name for advanced configuration
336+
std::wcout << L"Device: " << mi.szDevice << std::endl;
337+
```
338+
339+
#### macOS Implementation
340+
```objc
341+
// In platform/macos/display_macos.mm
342+
NSScreen* screen = static_cast<NSScreen*>(native);
343+
344+
// Access color space information
345+
NSColorSpace* colorSpace = [screen colorSpace];
346+
std::cout << "Color space: " << [[colorSpace localizedName] UTF8String] << std::endl;
319347
```
320348

321349
## Design Considerations
@@ -354,13 +382,37 @@ if (!native) {
354382
return;
355383
}
356384

357-
#ifdef _WIN32
358-
HWND hwnd = static_cast<HWND>(native);
359-
if (!IsWindow(hwnd)) {
360-
// Handle invalid window
361-
return;
362-
}
363-
#endif
385+
// Platform-specific validation would be in separate implementation files
386+
```
387+
388+
#### Windows Implementation
389+
```cpp
390+
// In platform/windows/window_windows.cpp
391+
HWND hwnd = static_cast<HWND>(native);
392+
if (!IsWindow(hwnd)) {
393+
// Handle invalid window
394+
return;
395+
}
396+
```
397+
398+
#### macOS Implementation
399+
```objc
400+
// In platform/macos/window_macos.mm
401+
NSWindow* nswindow = static_cast<NSWindow*>(native);
402+
if (!nswindow || ![nswindow isKindOfClass:[NSWindow class]]) {
403+
// Handle invalid window
404+
return;
405+
}
406+
```
407+
408+
#### Linux Implementation
409+
```cpp
410+
// In platform/linux/window_linux.cpp
411+
GtkWidget* gtkwindow = static_cast<GtkWidget*>(native);
412+
if (!GTK_IS_WINDOW(gtkwindow)) {
413+
// Handle invalid window
414+
return;
415+
}
364416
```
365417

366418
### Lifetime Considerations
@@ -384,7 +436,7 @@ manager.Destroy(window->GetId());
384436
1. **Document native types** - Comment what type is returned on each platform
385437
2. **Validate before casting** - Check for null, platform-specific validity
386438
3. **Don't store native handles** - They may become invalid when wrapper is destroyed
387-
4. **Use platform guards** - Always use `#ifdef` to ensure correct platform
439+
4. **Separate platform implementations** - Keep platform-specific code in `/platform/{windows|macos|linux}` directories
388440
5. **Prefer cross-platform API** - Only use native handles when absolutely necessary
389441
6. **Thread safety** - Native APIs may have threading restrictions
390442
7. **Keep it simple** - Minimize platform-specific code in user code
@@ -413,12 +465,10 @@ When documenting APIs that return native objects:
413465
* ```cpp
414466
* void* native = window->GetNativeObject();
415467
*
416-
* #ifdef _WIN32
417-
* HWND hwnd = static_cast<HWND>(native);
418-
* if (hwnd && IsWindow(hwnd)) {
419-
* SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
420-
* }
421-
* #endif
468+
* // Platform-specific implementations would be in separate files:
469+
* // Windows: platform/windows/window_windows.cpp
470+
* // macOS: platform/macos/window_macos.mm
471+
* // Linux: platform/linux/window_linux.cpp
422472
* ```
423473
*/
424474
void* GetNativeObject() const;
@@ -430,38 +480,33 @@ void* GetNativeObject() const;
430480

431481
```cpp
432482
// Bad - wrong type for platform
433-
#ifdef _WIN32
434-
NSWindow* window = static_cast<NSWindow*>(native); // Error!
435-
#endif
483+
// In Windows implementation file, casting to macOS type
484+
NSWindow* window = static_cast<NSWindow*>(native); // Error!
436485

437486
// Good - correct type for platform
438-
#ifdef _WIN32
439-
HWND hwnd = static_cast<HWND>(native);
440-
#endif
487+
// In platform/windows/window_windows.cpp
488+
HWND hwnd = static_cast<HWND>(native);
441489
```
442490

443-
### ❌ Don't Forget Platform Guards
491+
### ❌ Don't Mix Platform Code
444492

445493
```cpp
446-
// Bad - assumes Windows
494+
// Bad - mixing platform APIs in same file
447495
HWND hwnd = static_cast<HWND>(window->GetNativeObject());
496+
NSWindow* nswindow = static_cast<NSWindow*>(window->GetNativeObject()); // Wrong!
448497

449-
// Good - platform-specific
450-
#ifdef _WIN32
451-
HWND hwnd = static_cast<HWND>(window->GetNativeObject());
452-
#elif defined(__APPLE__)
453-
NSWindow* nswindow = static_cast<NSWindow*>(window->GetNativeObject());
454-
#endif
498+
// Good - separate platform implementations
499+
// Windows: platform/windows/window_windows.cpp
500+
// macOS: platform/macos/window_macos.mm
455501
```
456502

457503
### ❌ Don't Manage Native Lifetime Manually
458504

459505
```cpp
460506
// Bad - trying to destroy native object directly
461-
#ifdef _WIN32
462-
HWND hwnd = static_cast<HWND>(window->GetNativeObject());
463-
DestroyWindow(hwnd); // Wrapper still thinks it owns this!
464-
#endif
507+
// In platform/windows/window_windows.cpp
508+
HWND hwnd = static_cast<HWND>(window->GetNativeObject());
509+
DestroyWindow(hwnd); // Wrapper still thinks it owns this!
465510

466511
// Good - let wrapper manage lifetime
467512
manager.Destroy(window->GetId());

0 commit comments

Comments
 (0)