Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ add_subdirectory(src)
add_subdirectory(examples/display_example)
add_subdirectory(examples/window_example)
add_subdirectory(examples/keyboard_example)
add_subdirectory(examples/window_listener_test)
152 changes: 152 additions & 0 deletions docs/WindowListener.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# WindowListener API

The WindowListener API provides a way to listen for window events in the native API library. This implementation follows the existing event dispatcher pattern used throughout the library.

## Overview

The WindowManager class now includes event dispatching capabilities that allow you to listen for various window lifecycle events such as creation, destruction, focus changes, resizing, and movement.

## Supported Events

The following window events are supported:

- `WindowCreatedEvent` - Fired when a new window is created
- `WindowClosedEvent` - Fired when a window is closed
- `WindowFocusedEvent` - Fired when a window gains focus
- `WindowBlurredEvent` - Fired when a window loses focus
- `WindowMinimizedEvent` - Fired when a window is minimized
- `WindowMaximizedEvent` - Fired when a window is maximized
- `WindowRestoredEvent` - Fired when a window is restored from minimized/maximized state
- `WindowMovedEvent` - Fired when a window is moved (includes new position)
- `WindowResizedEvent` - Fired when a window is resized (includes new size)

## Usage

### Adding Listeners

You can add event listeners in two ways:

#### 1. Using Callback Functions (Recommended)

```cpp
#include "nativeapi.h"

using namespace nativeapi;

WindowManager window_manager;

// Add a callback listener for window creation
auto listener_id = window_manager.AddListener<WindowCreatedEvent>(
[](const WindowCreatedEvent& event) {
std::cout << "Window created with ID: " << event.GetWindowId() << std::endl;
}
);

// Add a callback listener for window resize
auto resize_listener_id = window_manager.AddListener<WindowResizedEvent>(
[](const WindowResizedEvent& event) {
Size new_size = event.GetNewSize();
std::cout << "Window " << event.GetWindowId() << " resized to "
<< new_size.width << "x" << new_size.height << std::endl;
}
);

// Add a callback listener for window move
auto move_listener_id = window_manager.AddListener<WindowMovedEvent>(
[](const WindowMovedEvent& event) {
Point new_pos = event.GetNewPosition();
std::cout << "Window " << event.GetWindowId() << " moved to ("
<< new_pos.x << ", " << new_pos.y << ")" << std::endl;
}
);
```

#### 2. Using Custom Listener Classes

```cpp
#include "nativeapi.h"

using namespace nativeapi;

class MyWindowListener : public TypedEventListener<WindowFocusedEvent> {
public:
void OnTypedEvent(const WindowFocusedEvent& event) override {
std::cout << "Window focused: " << event.GetWindowId() << std::endl;
}
};

WindowManager window_manager;
MyWindowListener my_listener;

// Add the listener
auto listener_id = window_manager.AddListener<WindowFocusedEvent>(&my_listener);
```

### Removing Listeners

```cpp
// Remove a specific listener by ID
bool success = window_manager.RemoveListener(listener_id);

// Remove all listeners for a specific event type
window_manager.RemoveAllListeners<WindowCreatedEvent>();

// Remove all listeners
window_manager.GetEventDispatcher().RemoveAllListeners();
```

### Event Properties

Each event provides access to relevant data:

```cpp
// WindowCreatedEvent, WindowClosedEvent, WindowFocusedEvent, etc.
WindowID id = event.GetWindowId();

// WindowMovedEvent
WindowID id = event.GetWindowId();
Point position = event.GetNewPosition();

// WindowResizedEvent
WindowID id = event.GetWindowId();
Size size = event.GetNewSize();
```

## Platform Support

### macOS
Full implementation using NSNotificationCenter to listen for NSWindow events:
- NSWindowDidBecomeKeyNotification
- NSWindowDidResignKeyNotification
- NSWindowDidMiniaturizeNotification
- NSWindowDidDeminiaturizeNotification
- NSWindowDidResizeNotification
- NSWindowDidMoveNotification
- NSWindowWillCloseNotification

### Windows
Stub implementation provided. Event monitoring not yet implemented.

### Linux
Stub implementation provided. Event monitoring not yet implemented.

## Example Application

See `examples/window_listener_test/main.cpp` for a complete example showing how to use the WindowListener API.

## Integration with Existing Code

The WindowListener API integrates seamlessly with the existing event system:

```cpp
// You can access the underlying event dispatcher for advanced usage
EventDispatcher& dispatcher = window_manager.GetEventDispatcher();

// Check listener counts
size_t count = window_manager.GetEventDispatcher().GetListenerCount<WindowCreatedEvent>();
size_t total = window_manager.GetEventDispatcher().GetTotalListenerCount();
```

## Thread Safety

The event dispatcher is thread-safe and supports both synchronous and asynchronous event dispatching. Window events are dispatched synchronously by default to ensure immediate notification of window state changes.
54 changes: 52 additions & 2 deletions src/platform/linux/window_manager_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,25 @@

namespace nativeapi {

WindowManager::WindowManager() {
// Private implementation for Linux (stub for now)
class WindowManager::WindowManagerImpl {
public:
WindowManagerImpl(WindowManager* manager) : manager_(manager) {}
~WindowManagerImpl() {}

void SetupEventMonitoring() {
// TODO: Implement Linux-specific event monitoring using GTK signals
}

void CleanupEventMonitoring() {
// TODO: Implement Linux-specific cleanup
}

private:
WindowManager* manager_;
};

WindowManager::WindowManager() : impl_(std::make_unique<WindowManagerImpl>(this)) {
// Try to initialize GTK if not already initialized
// In headless environments, this may fail, which is acceptable
if (!gdk_display_get_default()) {
Expand All @@ -29,9 +47,25 @@ WindowManager::WindowManager() {
// gtk_init_check returns FALSE if initialization failed (e.g., no display)
// This is acceptable for headless environments
}

SetupEventMonitoring();
}

WindowManager::~WindowManager() {
CleanupEventMonitoring();
}

void WindowManager::SetupEventMonitoring() {
impl_->SetupEventMonitoring();
}

WindowManager::~WindowManager() {}
void WindowManager::CleanupEventMonitoring() {
impl_->CleanupEventMonitoring();
}

void WindowManager::DispatchWindowEvent(const Event& event) {
event_dispatcher_.DispatchSync(event);
}

std::shared_ptr<Window> WindowManager::Get(WindowID id) {
auto it = windows_.find(id);
Expand Down Expand Up @@ -131,4 +165,20 @@ std::shared_ptr<Window> WindowManager::GetCurrent() {
return nullptr;
}

std::shared_ptr<Window> WindowManager::Create(const WindowOptions& options) {
// TODO: Implement Linux window creation using GTK
// For now, return nullptr as this is a stub implementation
return nullptr;
}

bool WindowManager::Destroy(WindowID id) {
auto it = windows_.find(id);
if (it != windows_.end()) {
// TODO: Implement proper GTK window destruction
windows_.erase(it);
return true;
}
return false;
}

} // namespace nativeapi
Loading