Skip to content

Commit 9230398

Browse files
committed
strata-shell: Added support for window resize.
1 parent f7a570a commit 9230398

4 files changed

Lines changed: 93 additions & 24 deletions

File tree

project.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@
4747
"tag": "main"
4848
},
4949
"skift-org/hideo": {
50-
"commit": "49bce7e695d1801c17e3e394010586b6bf99461e",
50+
"commit": "d48f33ae1ed8c43a5c59aed9a3defb107c6fbb4b",
5151
"git": "https://github.com/skift-org/hideo.git",
5252
"tag": "main"
5353
},
5454
"skift-org/karm": {
55-
"commit": "91b368c73f1f09e313660982d84a37a37b034e21",
55+
"commit": "f215f08199b37862d8e95e05a4eceeccba1c1142",
5656
"git": "https://github.com/skift-org/karm.git",
5757
"tag": "main"
5858
},

src/impls/impl-skift/app/app.cpp

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Karm.Core;
88
import Karm.Gfx;
99
import Karm.Sys;
1010
import Strata.Protos;
11+
import Karm.Logger;
1112

1213
namespace Karm::App::_Embed {
1314

@@ -19,6 +20,7 @@ struct SkiftWindow : Window {
1920
Rc<Strata::Protos::Surface> _surface;
2021
bool _dirty = false;
2122
bool _closed = false;
23+
Opt<Math::Vec2i> _shouldResize;
2224

2325
SkiftWindow(SkiftApplication& application, Strata::IShell::WindowId id, Rc<Strata::Protos::Surface> surface)
2426
: _application(application), _id(id), _surface(surface) {}
@@ -72,8 +74,6 @@ struct SkiftApplication : Application {
7274
}
7375

7476
Async::Task<Rc<Window>> createWindowAsync(WindowProps const& props, Async::CancellationToken ct) override {
75-
// NOTE: The Window API is synchronous, but Strata is async.
76-
// We use Sys::run to block until the window is created by the shell.
7777
auto [id, actual] = co_trya$(_endpoint->callAsync(
7878
_shell,
7979
Strata::IShell::WindowCreate{
@@ -102,23 +102,38 @@ struct SkiftApplication : Application {
102102
co_return Ok(window);
103103
}
104104

105-
void pollMessage(Rc<Handler> handler) {
106-
while (auto maybeMessage = _endpoint->tryRecv()) {
107-
if (maybeMessage->is<Strata::IShell::WindowEvent>()) {
108-
auto m = maybeMessage->unpack<Strata::IShell::WindowEvent>().unwrap();
109-
auto windowId = WindowId{m.window};
110-
111-
m.event.visit([&](auto const& event) {
112-
using T = Meta::RemoveConstVolatileRef<decltype(event)>;
113-
114-
if constexpr (Meta::Contains<T, MouseEvent, KeyboardEvent, TypeEvent>) {
115-
handler->handle<T>(windowId, event);
116-
} else if constexpr (Meta::Same<T, RequestCloseEvent>) {
117-
_exited = true;
118-
}
119-
});
105+
Res<> _handleWindowEvent(Sys::Message& message, Rc<Handler> handler) {
106+
auto [windowId, payload] = try$(message.unpack<Strata::IShell::WindowEvent>());
107+
payload.visit([&]<typename E>(E const& event) {
108+
using T = Meta::RemoveConstVolatileRef<E>;
109+
110+
if constexpr (Meta::Contains<T, MouseEvent, KeyboardEvent, TypeEvent>) {
111+
handler->handle<T>(App::WindowId{windowId}, event);
112+
} else if constexpr (Meta::Same<T, RequestCloseEvent>) {
113+
_exited = true;
120114
}
115+
});
116+
return Ok();
117+
}
118+
119+
Res<> _handleWindowUpdate(Sys::Message& message) {
120+
auto [windowId, props] = try$(message.unpack<Strata::IShell::WindowUpdate>());
121+
auto* window = try$(_windows.tryGet(windowId).okOr(Error::invalidInput("no such window")));
122+
// FIXME: We should probably have a separated hello message that pass stuff like color scheme and form factor
123+
App::formFactor = props.formFactor;
124+
window->_shouldResize = props.size;
125+
return Ok();
126+
}
127+
128+
Res<> _pollMessages(Rc<Handler> handler) {
129+
while (auto maybeMessage = _endpoint->tryRecv()) {
130+
auto& message = maybeMessage.unwrap();
131+
if (message.is<Strata::IShell::WindowEvent>())
132+
try$(_handleWindowEvent(message, handler));
133+
else if (message.is<Strata::IShell::WindowUpdate>())
134+
try$(_handleWindowUpdate(message));
121135
}
136+
return Ok();
122137
}
123138

124139
bool exited() {
@@ -128,15 +143,45 @@ struct SkiftApplication : Application {
128143
return true;
129144
}
130145

146+
Async::Task<> _handleWindowResizeAsync(Rc<Handler> handler, Async::CancellationToken ct) {
147+
for (auto [id, window] : _windows.iterUnordered()) {
148+
if (not window->_shouldResize)
149+
continue;
150+
151+
auto size = window->_shouldResize.unwrap();
152+
logDebug("new size {}", size);
153+
154+
auto newSurface = co_try$(Strata::Protos::Surface::create(size));
155+
156+
co_trya$(_endpoint->callAsync(
157+
_shell,
158+
Strata::IShell::WindowAttach{
159+
id,
160+
newSurface,
161+
},
162+
ct
163+
));
164+
165+
window->_surface = newSurface;
166+
window->_shouldResize = NONE;
167+
handler->handle<ResizeEvent>(window->id(), size);
168+
}
169+
170+
co_return Ok();
171+
}
172+
131173
Async::Task<> runAsync(Rc<Handler> handler, Async::CancellationToken ct) override {
132174
Duration const frameDuration = Duration::fromMSecs(16);
133175
Instant nextFrameTime = Sys::instant();
134176

135177
while (not exited()) {
136178
nextFrameTime = nextFrameTime + frameDuration;
137179

138-
pollMessage(handler);
180+
if (auto res = _pollMessages(handler); not res) {
181+
logError("failed to pull message from server: {}", res);
182+
}
139183

184+
co_trya$(_handleWindowResizeAsync(handler, ct));
140185
handler->update();
141186

142187
for (auto [id, window] : _windows.iterUnordered()) {

src/srvs/strata-protos/ishell.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export struct WindowAttach {
4040

4141
export struct WindowEvent {
4242
WindowId window;
43-
Union<None, App::MouseEvent> event;
43+
Union<None, App::MouseEvent, App::KeyboardEvent> event;
4444
};
4545

4646
export struct WindowFlip {

src/srvs/strata-shell/main.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,33 @@ struct ClientWindow : Hideo::Shell::Window {
129129
(void)_endpoint.send(_client, IShell::WindowEvent{_windowId, *it});
130130
}
131131

132+
void resize(Math::Vec2i size) override {
133+
if (size != bound.wh) {
134+
logDebug("resize: {}", size);
135+
_frontbuffer = Gfx::Surface::alloc(size);
136+
(void)_endpoint.send(
137+
_client,
138+
IShell::WindowUpdate{
139+
_windowId,
140+
{
141+
.size = size,
142+
.formFactor = App::formFactor,
143+
},
144+
}
145+
);
146+
}
147+
Window::resize(size);
148+
}
149+
132150
void attach(Rc<Protos::Surface> backbuffer) {
133151
_backbuffer = backbuffer;
134-
Gfx::blitUnsafe(_frontbuffer->mutPixels(), _backbuffer.unwrap()->pixels());
152+
flip();
153+
}
154+
155+
void flip() {
156+
// FIXME: Only blit the region that was updated
157+
auto region = _frontbuffer->mutPixels().bound().clipTo(_backbuffer.unwrap()->pixels().bound());
158+
Gfx::blitUnsafe(_frontbuffer->mutPixels().clip(region), _backbuffer.unwrap()->pixels().clip(region));
135159
}
136160
};
137161

@@ -230,6 +254,7 @@ struct Server {
230254

231255
auto instance = makeRc<ClientWindow>(_endpoint, message.header().from, windowSurface);
232256
instance->bound = Math::Recti{want.size}.center(_framebuffer->bound());
257+
instance->_windowId = windowId;
233258
_windows.put(windowId, instance);
234259
Hideo::Shell::Model::event(*_root, Hideo::Shell::AddInstance{instance});
235260

@@ -265,8 +290,7 @@ struct Server {
265290
auto [windowId, region] = try$(message.unpack<IShell::WindowFlip>());
266291

267292
auto instance = _windows.get(windowId);
268-
// FIXME: Only blit the region that was updated
269-
Gfx::blitUnsafe(instance->_frontbuffer->mutPixels(), instance->_backbuffer.unwrap()->pixels());
293+
instance->flip();
270294
Ui::shouldRepaint(*_root);
271295

272296
return Ok();

0 commit comments

Comments
 (0)