Skip to content

Commit fc0089a

Browse files
Copilotlijy91
andauthored
[WIP] 使用能用事件处理系统重构 DisplayManager 的事件监听 (#14)
* Initial plan * Refactor DisplayManager to use generic event system - core implementation Co-authored-by: lijy91 <[email protected]> * Complete DisplayManager event system refactoring with documentation and validation Co-authored-by: lijy91 <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: lijy91 <[email protected]>
1 parent bdc2c44 commit fc0089a

File tree

4 files changed

+260
-11
lines changed

4 files changed

+260
-11
lines changed

docs/DISPLAY_EVENT_USAGE.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# DisplayManager Event System Usage Examples
2+
3+
This document demonstrates how to use both the legacy DisplayListener interface and the new EventDispatcher-based event system.
4+
5+
## Legacy API (Backward Compatibility)
6+
7+
```cpp
8+
#include "nativeapi.h"
9+
using namespace nativeapi;
10+
11+
// Option 1: Implement DisplayListener interface
12+
class MyDisplayListener : public DisplayListener {
13+
public:
14+
void OnDisplayAdded(const Display& display) override {
15+
std::cout << "Display added: " << display.name << std::endl;
16+
}
17+
18+
void OnDisplayRemoved(const Display& display) override {
19+
std::cout << "Display removed: " << display.name << std::endl;
20+
}
21+
};
22+
23+
void useLegacyAPI() {
24+
DisplayManager displayManager;
25+
MyDisplayListener listener;
26+
27+
// Register listener
28+
displayManager.AddListener(&listener);
29+
30+
// Events will be received via OnDisplayAdded/OnDisplayRemoved
31+
32+
// Don't forget to remove when done
33+
displayManager.RemoveListener(&listener);
34+
}
35+
36+
// Option 2: Use DisplayEventHandler with callbacks
37+
void useLegacyCallbackAPI() {
38+
DisplayManager displayManager;
39+
40+
DisplayEventHandler handler(
41+
[](const Display& display) {
42+
std::cout << "Display added: " << display.name << std::endl;
43+
},
44+
[](const Display& display) {
45+
std::cout << "Display removed: " << display.name << std::endl;
46+
}
47+
);
48+
49+
displayManager.AddListener(&handler);
50+
// ... use the handler
51+
displayManager.RemoveListener(&handler);
52+
}
53+
```
54+
55+
## New Event API (Recommended)
56+
57+
```cpp
58+
#include "nativeapi.h"
59+
using namespace nativeapi;
60+
61+
// Option 1: Use callback functions (simplest)
62+
void useNewEventAPI() {
63+
DisplayManager displayManager;
64+
65+
// Register event listeners with callbacks
66+
auto addedListenerId = displayManager.AddEventListener<DisplayAddedEvent>(
67+
[](const DisplayAddedEvent& event) {
68+
const Display& display = event.GetDisplay();
69+
std::cout << "Display added: " << display.name << std::endl;
70+
});
71+
72+
auto removedListenerId = displayManager.AddEventListener<DisplayRemovedEvent>(
73+
[](const DisplayRemovedEvent& event) {
74+
const Display& display = event.GetDisplay();
75+
std::cout << "Display removed: " << display.name << std::endl;
76+
});
77+
78+
// Events will be dispatched automatically
79+
80+
// Remove listeners when done
81+
displayManager.RemoveEventListener(addedListenerId);
82+
displayManager.RemoveEventListener(removedListenerId);
83+
}
84+
85+
// Option 2: Implement TypedEventListener (for complex logic)
86+
class MyDisplayEventListener : public TypedEventListener<DisplayAddedEvent> {
87+
public:
88+
void OnTypedEvent(const DisplayAddedEvent& event) override {
89+
const Display& display = event.GetDisplay();
90+
std::cout << "New display detected: " << display.name << std::endl;
91+
// Complex logic here...
92+
}
93+
};
94+
95+
void useNewEventAPIWithListener() {
96+
DisplayManager displayManager;
97+
MyDisplayEventListener listener;
98+
99+
auto listenerId = displayManager.AddEventListener<DisplayAddedEvent>(&listener);
100+
101+
// ... use
102+
103+
displayManager.RemoveEventListener(listenerId);
104+
}
105+
106+
// Option 3: Use EventDispatcher directly
107+
void useEventDispatcherDirectly() {
108+
DisplayManager displayManager;
109+
EventDispatcher& dispatcher = displayManager.GetEventDispatcher();
110+
111+
auto listenerId = dispatcher.AddListener<DisplayAddedEvent>(
112+
[](const DisplayAddedEvent& event) {
113+
// Handle event
114+
});
115+
116+
// You can also dispatch custom events if needed
117+
Display customDisplay;
118+
customDisplay.name = "Custom Display";
119+
dispatcher.DispatchSync<DisplayAddedEvent>(customDisplay);
120+
121+
dispatcher.RemoveListener(listenerId);
122+
}
123+
```
124+
125+
## Migration Guide
126+
127+
### From Legacy to New API
128+
129+
```cpp
130+
// OLD WAY
131+
class OldListener : public DisplayListener {
132+
void OnDisplayAdded(const Display& display) override {
133+
handleDisplayAdded(display);
134+
}
135+
void OnDisplayRemoved(const Display& display) override {
136+
handleDisplayRemoved(display);
137+
}
138+
};
139+
140+
DisplayManager manager;
141+
OldListener listener;
142+
manager.AddListener(&listener);
143+
144+
// NEW WAY
145+
DisplayManager manager;
146+
auto addedId = manager.AddEventListener<DisplayAddedEvent>(
147+
[](const DisplayAddedEvent& event) {
148+
handleDisplayAdded(event.GetDisplay());
149+
});
150+
auto removedId = manager.AddEventListener<DisplayRemovedEvent>(
151+
[](const DisplayRemovedEvent& event) {
152+
handleDisplayRemoved(event.GetDisplay());
153+
});
154+
```
155+
156+
### Benefits of New API
157+
158+
1. **Type Safety**: Compile-time checking of event types
159+
2. **Flexibility**: Can use lambdas, function pointers, or listener classes
160+
3. **Advanced Features**: Async dispatch, listener management by ID
161+
4. **Consistency**: Same event system used across the entire library
162+
5. **Extensibility**: Easy to add new event types without changing interfaces
163+
164+
### Backward Compatibility
165+
166+
The legacy DisplayListener interface is fully supported and will continue to work. Both systems can be used simultaneously - events will be dispatched to both old and new listeners.
167+
168+
## Best Practices
169+
170+
1. **Prefer the new event API** for new code
171+
2. **Use callback functions** for simple event handling
172+
3. **Use TypedEventListener classes** for complex event handling logic
173+
4. **Always remove listeners** to prevent memory leaks
174+
5. **Store listener IDs** returned by AddEventListener for later removal
175+
6. **Consider using RAII** to automatically manage listener lifetimes
176+
177+
## Event Types
178+
179+
- `DisplayAddedEvent`: Fired when a display is connected
180+
- `DisplayRemovedEvent`: Fired when a display is disconnected
181+
182+
Both events provide access to the `Display` object via `GetDisplay()` method.

src/display_manager.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,26 @@ void DisplayManager::NotifyListeners(
1919
}
2020
}
2121

22+
void DisplayManager::DispatchDisplayAddedEvent(const Display& display) {
23+
// Dispatch through the new event system
24+
event_dispatcher_.DispatchSync<DisplayAddedEvent>(display);
25+
26+
// Also notify old-style listeners for backward compatibility
27+
NotifyListeners([&display](DisplayListener* listener) {
28+
listener->OnDisplayAdded(display);
29+
});
30+
}
31+
32+
void DisplayManager::DispatchDisplayRemovedEvent(const Display& display) {
33+
// Dispatch through the new event system
34+
event_dispatcher_.DispatchSync<DisplayRemovedEvent>(display);
35+
36+
// Also notify old-style listeners for backward compatibility
37+
NotifyListeners([&display](DisplayListener* listener) {
38+
listener->OnDisplayRemoved(display);
39+
});
40+
}
41+
2242
DisplayEventHandler::DisplayEventHandler(
2343
std::function<void(const Display&)> onDisplayAddedCallback,
2444
std::function<void(const Display&)> onDisplayRemovedCallback)

src/display_manager.h

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,33 @@
66
#include <vector>
77

88
#include "display.h"
9+
#include "event.h"
10+
#include "event_dispatcher.h"
911
#include "geometry.h"
1012

1113
namespace nativeapi {
1214

15+
// Event classes for display changes
16+
class DisplayAddedEvent : public TypedEvent<DisplayAddedEvent> {
17+
public:
18+
explicit DisplayAddedEvent(const Display& display) : display_(display) {}
19+
20+
const Display& GetDisplay() const { return display_; }
21+
22+
private:
23+
Display display_;
24+
};
25+
26+
class DisplayRemovedEvent : public TypedEvent<DisplayRemovedEvent> {
27+
public:
28+
explicit DisplayRemovedEvent(const Display& display) : display_(display) {}
29+
30+
const Display& GetDisplay() const { return display_; }
31+
32+
private:
33+
Display display_;
34+
};
35+
1336
// DisplayListener is an interface that can be implemented by classes that want
1437
// to listen for display events.
1538
class DisplayListener {
@@ -39,10 +62,34 @@ class DisplayManager {
3962
// Remove a listener from the display manager
4063
void RemoveListener(DisplayListener* listener);
4164

65+
// Event dispatcher methods for the new system
66+
template <typename EventType>
67+
size_t AddEventListener(TypedEventListener<EventType>* listener) {
68+
return event_dispatcher_.AddListener<EventType>(listener);
69+
}
70+
71+
template <typename EventType>
72+
size_t AddEventListener(std::function<void(const EventType&)> callback) {
73+
return event_dispatcher_.AddListener<EventType>(std::move(callback));
74+
}
75+
76+
bool RemoveEventListener(size_t listener_id) {
77+
return event_dispatcher_.RemoveListener(listener_id);
78+
}
79+
80+
// Get the event dispatcher (for advanced usage)
81+
EventDispatcher& GetEventDispatcher() { return event_dispatcher_; }
82+
4283
private:
4384
std::vector<Display> displays_;
44-
std::vector<DisplayListener*> listeners_;
85+
std::vector<DisplayListener*> listeners_; // For backward compatibility
86+
EventDispatcher event_dispatcher_; // New event system
87+
4588
void NotifyListeners(std::function<void(DisplayListener*)> callback);
89+
90+
// New event dispatch methods
91+
void DispatchDisplayAddedEvent(const Display& display);
92+
void DispatchDisplayRemovedEvent(const Display& display);
4693
};
4794

4895
// DisplayEventHandler is an implementation of DisplayListener that uses

src/platform/macos/display_manager_macos.mm

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ static Display CreateDisplayFromNSScreen(NSScreen* screen, bool isPrimary) {
4040
// Set position and size using geometry types
4141
display.position = {frame.origin.x, frame.origin.y};
4242
display.size = {frame.size.width, frame.size.height};
43-
display.workArea = {visibleFrame.origin.x, visibleFrame.origin.y,
44-
visibleFrame.size.height, visibleFrame.size.width};
43+
display.workArea = {visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.height,
44+
visibleFrame.size.width};
4545
display.scaleFactor = scaleFactor;
4646
display.isPrimary = isPrimary;
4747

@@ -56,7 +56,7 @@ static Display CreateDisplayFromNSScreen(NSScreen* screen, bool isPrimary) {
5656
CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(displayID);
5757
if (displayMode) {
5858
double refreshRate = CGDisplayModeGetRefreshRate(displayMode);
59-
display.refreshRate = refreshRate > 0 ? (int)refreshRate : 60; // Default to 60Hz if unknown
59+
display.refreshRate = refreshRate > 0 ? (int)refreshRate : 60; // Default to 60Hz if unknown
6060
CGDisplayModeRelease(displayMode);
6161
}
6262

@@ -81,11 +81,13 @@ static Display CreateDisplayFromNSScreen(NSScreen* screen, bool isPrimary) {
8181

8282
// Use display name as model for now
8383
display.model = display.name;
84-
display.serialNumber = ""; // Not easily available without deprecated APIs
84+
display.serialNumber = ""; // Not easily available without deprecated APIs
8585

8686
// Set default values if hardware info couldn't be retrieved
87-
if (display.manufacturer.empty()) display.manufacturer = "Unknown";
88-
if (display.model.empty()) display.model = "Unknown";
87+
if (display.manufacturer.empty())
88+
display.manufacturer = "Unknown";
89+
if (display.model.empty())
90+
display.model = "Unknown";
8991

9092
return display;
9193
}
@@ -109,8 +111,7 @@ static Display CreateDisplayFromNSScreen(NSScreen* screen, bool isPrimary) {
109111
old_ids.insert(d.id);
110112
for (const auto& d : new_displays) {
111113
if (old_ids.find(d.id) == old_ids.end()) {
112-
NotifyListeners(
113-
[d](DisplayListener* listener) { listener->OnDisplayAdded(d); });
114+
DispatchDisplayAddedEvent(d);
114115
}
115116
}
116117

@@ -120,8 +121,7 @@ static Display CreateDisplayFromNSScreen(NSScreen* screen, bool isPrimary) {
120121
new_ids.insert(d.id);
121122
for (const auto& d : old_displays) {
122123
if (new_ids.find(d.id) == new_ids.end()) {
123-
NotifyListeners(
124-
[d](DisplayListener* listener) { listener->OnDisplayRemoved(d); });
124+
DispatchDisplayRemovedEvent(d);
125125
}
126126
}
127127

0 commit comments

Comments
 (0)