mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-10 21:01:49 +00:00
parent
d6cb9cf854
commit
9ce7c72c7c
@ -38,6 +38,8 @@ class Dialog::Sandboxed_runtime : Noncopyable
|
||||
|
||||
template <typename T> class Event_handler;
|
||||
|
||||
using Start_name = String<128>;
|
||||
|
||||
private:
|
||||
|
||||
Env &_env;
|
||||
@ -96,219 +98,15 @@ class Dialog::Sandboxed_runtime : Noncopyable
|
||||
Rom_service _rom_service;
|
||||
Report_service _report_service;
|
||||
|
||||
public:
|
||||
|
||||
Sandboxed_runtime(Env &, Allocator &, Sandbox &);
|
||||
|
||||
/**
|
||||
* Respond to sandbox state changes
|
||||
*
|
||||
* \return true if the sandbox configuration needs to be updated
|
||||
*/
|
||||
bool apply_sandbox_state(Xml_node const &);
|
||||
|
||||
void gen_start_nodes(Xml_generator &) const;
|
||||
};
|
||||
|
||||
|
||||
class Dialog::Sandboxed_runtime::Report_session : public Session_object<Report::Session>
|
||||
{
|
||||
public:
|
||||
|
||||
struct Handler : Interface, Genode::Noncopyable
|
||||
{
|
||||
virtual void handle_report() = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Attached_ram_dataspace _client_ds;
|
||||
Attached_ram_dataspace _local_ds;
|
||||
|
||||
Constructible<Xml_node> _xml { }; /* points inside _local_ds */
|
||||
|
||||
Handler &_handler;
|
||||
|
||||
|
||||
/*******************************
|
||||
** Report::Session interface **
|
||||
*******************************/
|
||||
|
||||
Dataspace_capability dataspace() override { return _client_ds.cap(); }
|
||||
|
||||
void submit(size_t length) override
|
||||
{
|
||||
size_t const num_bytes = min(_client_ds.size(), length);
|
||||
|
||||
memcpy(_local_ds.local_addr<char>(), _client_ds.local_addr<char>(),
|
||||
num_bytes);
|
||||
|
||||
_xml.destruct();
|
||||
|
||||
try { _xml.construct(_local_ds.local_addr<char>(), num_bytes); }
|
||||
catch (...) { }
|
||||
|
||||
_handler.handle_report();
|
||||
}
|
||||
|
||||
void response_sigh(Signal_context_capability) override { }
|
||||
|
||||
size_t obtain_response() override { return 0; }
|
||||
|
||||
public:
|
||||
|
||||
template <typename... ARGS>
|
||||
Report_session(Env &env, Handler &handler,
|
||||
Entrypoint &ep, Resources const &resources,
|
||||
ARGS &&... args)
|
||||
:
|
||||
Session_object(ep, resources, args...),
|
||||
_client_ds(env.ram(), env.rm(), resources.ram_quota.value/2),
|
||||
_local_ds (env.ram(), env.rm(), resources.ram_quota.value/2),
|
||||
_handler(handler)
|
||||
{ }
|
||||
|
||||
template <typename FN>
|
||||
void with_xml(FN const &fn) const
|
||||
{
|
||||
if (_xml.constructed())
|
||||
fn(*_xml);
|
||||
else
|
||||
fn(Xml_node("<empty/>"));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Dialog::Sandboxed_runtime::View : private Views::Element
|
||||
{
|
||||
private:
|
||||
|
||||
/* needed for privately inheriting 'Views::Element' */
|
||||
friend class Dictionary<View, Top_level_dialog::Name>;
|
||||
friend class Avl_node<View>;
|
||||
friend class Avl_tree<View>;
|
||||
friend class Sandboxed_runtime;
|
||||
|
||||
Env &_env;
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
Event::Seq_number &_global_seq_number;
|
||||
|
||||
Optional_event_handler &_optional_event_handler;
|
||||
|
||||
Top_level_dialog &_dialog;
|
||||
|
||||
bool _dialog_hovered = false; /* used to cut hover feedback loop */
|
||||
|
||||
/* sequence numbers to correlate hover info with click/clack events */
|
||||
Event::Seq_number _hover_seq_number { };
|
||||
Constructible<Event::Seq_number> _click_seq_number { };
|
||||
Constructible<Event::Seq_number> _clack_seq_number { };
|
||||
|
||||
bool _click_delivered = false; /* used to deliver each click only once */
|
||||
|
||||
bool _dragged() const
|
||||
{
|
||||
return _click_seq_number.constructed()
|
||||
&& *_click_seq_number == _global_seq_number
|
||||
&& _click_delivered;
|
||||
}
|
||||
|
||||
bool _hover_observable_without_click = false;
|
||||
|
||||
struct Rom_producer : Dynamic_rom_session::Xml_producer
|
||||
{
|
||||
View const &_view;
|
||||
|
||||
Rom_producer(View const &view)
|
||||
:
|
||||
Dynamic_rom_session::Xml_producer("dialog"),
|
||||
_view(view)
|
||||
{ }
|
||||
|
||||
void produce_xml(Xml_generator &xml) override
|
||||
{
|
||||
_view._with_dialog_hover([&] (Xml_node const &hover) {
|
||||
|
||||
Event::Dragged const dragged { _view._dragged() };
|
||||
|
||||
bool const supply_hover = _view._hover_observable_without_click
|
||||
|| dragged.value;
|
||||
|
||||
static Xml_node omitted_hover("<hover/>");
|
||||
|
||||
At const at { _view._global_seq_number,
|
||||
supply_hover ? hover : omitted_hover };
|
||||
|
||||
Scope<> top_level_scope(xml, at, dragged, { _view._dialog.name });
|
||||
|
||||
_view._dialog.view(top_level_scope);
|
||||
});
|
||||
}
|
||||
} _dialog_producer { *this };
|
||||
|
||||
Dynamic_rom_session _dialog_rom_session {
|
||||
_env.ep(), _env.ram(), _env.rm(), _dialog_producer };
|
||||
|
||||
template <typename T>
|
||||
struct Hover_handler : Report_session::Handler
|
||||
{
|
||||
T &_obj;
|
||||
void (T::*_member) ();
|
||||
|
||||
Hover_handler(T &obj, void (T::*member)())
|
||||
: _obj(obj), _member(member) { }
|
||||
|
||||
void handle_report() override
|
||||
{
|
||||
(_obj.*_member)();
|
||||
}
|
||||
};
|
||||
|
||||
Constructible<Report_session> _hover_report_session { };
|
||||
|
||||
template <typename FN>
|
||||
void _with_dialog_hover(FN const &fn) const
|
||||
{
|
||||
bool done = false;
|
||||
|
||||
if (_hover_report_session.constructed())
|
||||
_hover_report_session->with_xml([&] (Xml_node const &hover) {
|
||||
hover.with_optional_sub_node("dialog", [&] (Xml_node const &dialog) {
|
||||
fn(dialog);
|
||||
done = true; }); });
|
||||
|
||||
if (!done)
|
||||
fn(Xml_node("<empty/>"));
|
||||
}
|
||||
|
||||
void _handle_input_event(Input::Event const &);
|
||||
|
||||
void _handle_hover();
|
||||
|
||||
Hover_handler<View> _hover_handler { *this, &View::_handle_hover };
|
||||
|
||||
void _try_handle_click_and_clack();
|
||||
|
||||
struct Menu_view_state
|
||||
{
|
||||
using Start_name = String<128>;
|
||||
|
||||
Start_name const name;
|
||||
Ram_quota const initial_ram;
|
||||
Cap_quota const initial_caps;
|
||||
Ram_quota const initial_ram { 4*1024*1024 };
|
||||
Cap_quota const initial_caps { 100 };
|
||||
|
||||
Ram_quota ram = initial_ram;
|
||||
Cap_quota caps = initial_caps;
|
||||
|
||||
int xpos = 0, ypos = 0;
|
||||
|
||||
unsigned min_width = 0, min_height = 0;
|
||||
|
||||
bool opaque = false;
|
||||
Color background { };
|
||||
|
||||
unsigned version = 0;
|
||||
|
||||
void trigger_restart()
|
||||
@ -348,45 +146,226 @@ class Dialog::Sandboxed_runtime::View : private Views::Element
|
||||
return result;
|
||||
}
|
||||
|
||||
void gen_start_node(Xml_generator &) const;
|
||||
void gen_start_node(Xml_generator &, Views const &) const;
|
||||
|
||||
} _menu_view_state;
|
||||
|
||||
class Report_session : public Session_object<Report::Session>
|
||||
{
|
||||
public:
|
||||
|
||||
struct Handler : Interface, Genode::Noncopyable
|
||||
{
|
||||
virtual void handle_report() = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Attached_ram_dataspace _client_ds;
|
||||
Attached_ram_dataspace _local_ds;
|
||||
|
||||
Constructible<Xml_node> _xml { }; /* points inside _local_ds */
|
||||
|
||||
Handler &_handler;
|
||||
|
||||
|
||||
/*******************************
|
||||
** Report::Session interface **
|
||||
*******************************/
|
||||
|
||||
Dataspace_capability dataspace() override { return _client_ds.cap(); }
|
||||
|
||||
void submit(size_t length) override
|
||||
{
|
||||
size_t const num_bytes = min(_client_ds.size(), length);
|
||||
|
||||
memcpy(_local_ds.local_addr<char>(), _client_ds.local_addr<char>(),
|
||||
num_bytes);
|
||||
|
||||
_xml.destruct();
|
||||
|
||||
try { _xml.construct(_local_ds.local_addr<char>(), num_bytes); }
|
||||
catch (...) { }
|
||||
|
||||
_handler.handle_report();
|
||||
}
|
||||
|
||||
void response_sigh(Signal_context_capability) override { }
|
||||
|
||||
size_t obtain_response() override { return 0; }
|
||||
|
||||
public:
|
||||
|
||||
template <typename... ARGS>
|
||||
Report_session(Env &env, Handler &handler,
|
||||
Entrypoint &ep, Resources const &resources,
|
||||
ARGS &&... args)
|
||||
:
|
||||
Session_object(ep, resources, args...),
|
||||
_client_ds(env.ram(), env.rm(), resources.ram_quota.value/2),
|
||||
_local_ds (env.ram(), env.rm(), resources.ram_quota.value/2),
|
||||
_handler(handler)
|
||||
{ }
|
||||
|
||||
template <typename FN>
|
||||
void with_xml(FN const &fn) const
|
||||
{
|
||||
if (_xml.constructed())
|
||||
fn(*_xml);
|
||||
else
|
||||
fn(Xml_node("<empty/>"));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Hover_handler : Report_session::Handler
|
||||
{
|
||||
T &_obj;
|
||||
void (T::*_member) ();
|
||||
|
||||
Hover_handler(T &obj, void (T::*member)())
|
||||
: _obj(obj), _member(member) { }
|
||||
|
||||
void handle_report() override
|
||||
{
|
||||
(_obj.*_member)();
|
||||
}
|
||||
};
|
||||
|
||||
Top_level_dialog::Name _hovered_dialog { };
|
||||
|
||||
Hover_handler<Sandboxed_runtime> _hover_handler {
|
||||
*this, &Sandboxed_runtime::_handle_hover };
|
||||
|
||||
void _handle_hover();
|
||||
|
||||
Constructible<Report_session> _hover_report_session { };
|
||||
|
||||
Event::Seq_number _hover_seq_number { };
|
||||
|
||||
public:
|
||||
|
||||
struct Attr { Start_name name; };
|
||||
|
||||
Sandboxed_runtime(Env &, Allocator &, Sandbox &,
|
||||
Attr const &attr = { "view" });
|
||||
|
||||
/**
|
||||
* Respond to sandbox state changes
|
||||
*
|
||||
* \return true if the sandbox configuration needs to be updated
|
||||
*/
|
||||
bool apply_sandbox_state(Xml_node const &);
|
||||
|
||||
void gen_start_nodes(Xml_generator &) const;
|
||||
};
|
||||
|
||||
|
||||
class Dialog::Sandboxed_runtime::View : private Views::Element
|
||||
{
|
||||
private:
|
||||
|
||||
/* needed for privately inheriting 'Views::Element' */
|
||||
friend class Dictionary<View, Top_level_dialog::Name>;
|
||||
friend class Avl_node<View>;
|
||||
friend class Avl_tree<View>;
|
||||
friend class Sandboxed_runtime;
|
||||
|
||||
Env &_env;
|
||||
|
||||
Sandboxed_runtime &_runtime;
|
||||
|
||||
Top_level_dialog &_dialog;
|
||||
|
||||
bool _dialog_hovered = false;
|
||||
|
||||
/* sequence numbers to correlate hover info with click/clack events */
|
||||
Constructible<Event::Seq_number> _click_seq_number { };
|
||||
Constructible<Event::Seq_number> _clack_seq_number { };
|
||||
|
||||
bool _click_delivered = false; /* used to deliver each click only once */
|
||||
|
||||
bool _dragged() const
|
||||
{
|
||||
return _click_seq_number.constructed()
|
||||
&& *_click_seq_number == _runtime._global_seq_number
|
||||
&& _click_delivered;
|
||||
}
|
||||
|
||||
bool _hover_observable_without_click = false;
|
||||
|
||||
void _with_dialog_hover(auto const &fn) const
|
||||
{
|
||||
bool done = false;
|
||||
|
||||
if (_runtime._hover_report_session.constructed())
|
||||
_runtime._hover_report_session->with_xml([&] (Xml_node const &hover) {
|
||||
hover.with_optional_sub_node("dialog", [&] (Xml_node const &dialog) {
|
||||
fn(dialog);
|
||||
done = true; }); });
|
||||
|
||||
if (!done)
|
||||
fn(Xml_node("<empty/>"));
|
||||
}
|
||||
|
||||
struct Rom_producer : Dynamic_rom_session::Xml_producer
|
||||
{
|
||||
View const &_view;
|
||||
|
||||
Rom_producer(View const &view)
|
||||
:
|
||||
Dynamic_rom_session::Xml_producer("dialog"),
|
||||
_view(view)
|
||||
{ }
|
||||
|
||||
void produce_xml(Xml_generator &xml) override
|
||||
{
|
||||
_view._with_dialog_hover([&] (Xml_node const &hover) {
|
||||
|
||||
Event::Dragged const dragged { _view._dragged() };
|
||||
|
||||
bool const supply_hover = _view._hover_observable_without_click
|
||||
|| dragged.value;
|
||||
|
||||
static Xml_node omitted_hover("<hover/>");
|
||||
|
||||
At const at { _view._runtime._global_seq_number,
|
||||
supply_hover ? hover : omitted_hover };
|
||||
|
||||
Scope<> top_level_scope(xml, at, dragged, { _view._dialog.name });
|
||||
|
||||
_view._dialog.view(top_level_scope);
|
||||
});
|
||||
}
|
||||
} _dialog_producer { *this };
|
||||
|
||||
Dynamic_rom_session _dialog_rom_session {
|
||||
_env.ep(), _env.ram(), _env.rm(), _dialog_producer };
|
||||
|
||||
void _gen_menu_view_dialog(Xml_generator &) const;
|
||||
void _gen_menu_view_routes(Xml_generator &) const;
|
||||
|
||||
void _handle_input_event(Input::Event const &);
|
||||
|
||||
void _handle_hover();
|
||||
void _leave();
|
||||
void _try_handle_click_and_clack();
|
||||
|
||||
Registry<Gui_session> _gui_sessions { };
|
||||
|
||||
public:
|
||||
|
||||
int &xpos = _menu_view_state.xpos;
|
||||
int &ypos = _menu_view_state.ypos;
|
||||
unsigned &min_width = _menu_view_state.min_width;
|
||||
unsigned &min_height = _menu_view_state.min_height;
|
||||
bool &opaque = _menu_view_state.opaque;
|
||||
Color &background = _menu_view_state.background;
|
||||
|
||||
struct Attr
|
||||
{
|
||||
bool opaque;
|
||||
Ram_quota initial_ram;
|
||||
};
|
||||
|
||||
View(Sandboxed_runtime &runtime, Top_level_dialog &dialog, Attr const attr)
|
||||
:
|
||||
Views::Element(runtime._views, dialog.name),
|
||||
_env(runtime._env), _alloc(runtime._alloc),
|
||||
_global_seq_number(runtime._global_seq_number),
|
||||
_optional_event_handler(runtime._optional_event_handler),
|
||||
_dialog(dialog),
|
||||
_menu_view_state({
|
||||
.name = dialog.name,
|
||||
.initial_ram = attr.initial_ram,
|
||||
.initial_caps = Cap_quota { 200 }
|
||||
})
|
||||
{ }
|
||||
int xpos { };
|
||||
int ypos { };
|
||||
unsigned min_width { };
|
||||
unsigned min_height { };
|
||||
bool opaque { };
|
||||
Color background { };
|
||||
|
||||
View(Sandboxed_runtime &runtime, Top_level_dialog &dialog)
|
||||
:
|
||||
View(runtime, dialog, Attr { .opaque = false,
|
||||
.initial_ram = { 4*1024*1024 } })
|
||||
Views::Element(runtime._views, dialog.name),
|
||||
_env(runtime._env), _runtime(runtime), _dialog(dialog)
|
||||
{ }
|
||||
|
||||
~View();
|
||||
|
@ -44,10 +44,7 @@ struct Touch_keyboard::Main : Top_level_dialog
|
||||
|
||||
Runtime _runtime { _env, _heap };
|
||||
|
||||
Runtime::View _view { _runtime, *this, Runtime::View::Attr {
|
||||
.opaque = true,
|
||||
.initial_ram = Ram_quota { 4*1024*1024 }
|
||||
} };
|
||||
Runtime::View _view { _runtime, *this };
|
||||
|
||||
/*
|
||||
* Top_level_dialog interface
|
||||
|
@ -82,8 +82,9 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session>
|
||||
if (clack(ev)) _clicked = false;
|
||||
|
||||
if (orig_clicked != _clicked) {
|
||||
_view._global_seq_number.value++;
|
||||
_input_component.submit(Input::Seq_number { _view._global_seq_number.value });
|
||||
Event::Seq_number &global_seq = _view._runtime._global_seq_number;
|
||||
global_seq.value++;
|
||||
_input_component.submit(Input::Seq_number { global_seq.value });
|
||||
}
|
||||
|
||||
/* local event (click/clack) handling */
|
||||
@ -161,12 +162,14 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session>
|
||||
};
|
||||
|
||||
|
||||
Sandboxed_runtime::Sandboxed_runtime(Env &env, Allocator &alloc, Sandbox &sandbox)
|
||||
Sandboxed_runtime::Sandboxed_runtime(Env &env, Allocator &alloc, Sandbox &sandbox,
|
||||
Attr const &attr)
|
||||
:
|
||||
_env(env), _alloc(alloc), _sandbox(sandbox),
|
||||
_gui_service (_sandbox, _gui_handler),
|
||||
_rom_service (_sandbox, _rom_handler),
|
||||
_report_service(_sandbox, _report_handler)
|
||||
_report_service(_sandbox, _report_handler),
|
||||
_menu_view_state { .name = attr.name }
|
||||
{ }
|
||||
|
||||
|
||||
@ -175,14 +178,8 @@ bool Sandboxed_runtime::apply_sandbox_state(Xml_node const &state)
|
||||
bool reconfiguration_needed = false;
|
||||
|
||||
state.for_each_sub_node("child", [&] (Xml_node const &child) {
|
||||
using Name = Top_level_dialog::Name;
|
||||
Name const name = child.attribute_value("name", Name());
|
||||
_views.with_element(name,
|
||||
[&] (View &view) {
|
||||
if (view._menu_view_state.apply_child_state_report(child))
|
||||
reconfiguration_needed = true; },
|
||||
[&] /* no view named after this child */ { });
|
||||
});
|
||||
if (_menu_view_state.apply_child_state_report(child))
|
||||
reconfiguration_needed = true; });
|
||||
|
||||
return reconfiguration_needed;
|
||||
}
|
||||
@ -191,12 +188,10 @@ bool Sandboxed_runtime::apply_sandbox_state(Xml_node const &state)
|
||||
void Sandboxed_runtime::_handle_rom_service()
|
||||
{
|
||||
_rom_service.for_each_requested_session([&] (Rom_service::Request &request) {
|
||||
if (request.label.last_element() == "dialog") {
|
||||
_views.with_element(request.label.prefix(),
|
||||
[&] (View &view) {
|
||||
request.deliver_session(view._dialog_rom_session); },
|
||||
[&] /* no view named after this child */ { });
|
||||
}
|
||||
_views.with_element(request.label.last_element(),
|
||||
[&] (View &view) {
|
||||
request.deliver_session(view._dialog_rom_session); },
|
||||
[&] { });
|
||||
});
|
||||
|
||||
_rom_service.for_each_session_to_close([&] (Dynamic_rom_session &) {
|
||||
@ -209,14 +204,10 @@ void Sandboxed_runtime::_handle_rom_service()
|
||||
void Sandboxed_runtime::_handle_report_service()
|
||||
{
|
||||
_report_service.for_each_requested_session([&] (Report_service::Request &request) {
|
||||
if (request.label.last_element() == "hover") {
|
||||
_views.with_element(request.label.prefix(),
|
||||
[&] (View &view) {
|
||||
view._hover_report_session.construct(_env, view._hover_handler, _env.ep(),
|
||||
request.resources, "", request.diag);
|
||||
request.deliver_session(*view._hover_report_session);
|
||||
},
|
||||
[&] /* no view named after this child */ { });
|
||||
if (request.label == Start_name { _menu_view_state.name, " -> hover" }) {
|
||||
_hover_report_session.construct(_env, _hover_handler, _env.ep(),
|
||||
request.resources, "", request.diag);
|
||||
request.deliver_session(*_hover_report_session);
|
||||
}
|
||||
});
|
||||
|
||||
@ -230,16 +221,16 @@ void Sandboxed_runtime::_handle_report_service()
|
||||
void Sandboxed_runtime::_handle_gui_service()
|
||||
{
|
||||
_gui_service.for_each_requested_session([&] (Gui_service::Request &request) {
|
||||
_views.with_element(request.label.prefix(),
|
||||
_views.with_element(request.label.last_element(),
|
||||
[&] (View &view) {
|
||||
Gui_session &session = *new (_alloc)
|
||||
Gui_session(_env, view, _env.ep(),
|
||||
request.resources, "", request.diag);
|
||||
request.deliver_session(session);
|
||||
},
|
||||
[&] {
|
||||
warning("unexpected GUI-sesssion request, label=", request.label);
|
||||
});
|
||||
[&] {
|
||||
warning("unexpected GUI-sesssion request, label=", request.label);
|
||||
});
|
||||
});
|
||||
|
||||
_gui_service.for_each_upgraded_session([&] (Gui_session &session,
|
||||
@ -257,12 +248,11 @@ void Sandboxed_runtime::_handle_gui_service()
|
||||
|
||||
void Sandboxed_runtime::gen_start_nodes(Xml_generator &xml) const
|
||||
{
|
||||
_views.for_each([&] (View const &view) {
|
||||
view._menu_view_state.gen_start_node(xml); });
|
||||
_menu_view_state.gen_start_node(xml, _views);
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::View::Menu_view_state::gen_start_node(Xml_generator &xml) const
|
||||
void Sandboxed_runtime::Menu_view_state::gen_start_node(Xml_generator &xml, Views const &views) const
|
||||
{
|
||||
xml.node("start", [&] () {
|
||||
|
||||
@ -280,14 +270,6 @@ void Sandboxed_runtime::View::Menu_view_state::gen_start_node(Xml_generator &xml
|
||||
|
||||
xml.node("config", [&] () {
|
||||
|
||||
if (xpos) xml.attribute("xpos", xpos);
|
||||
if (ypos) xml.attribute("ypos", ypos);
|
||||
if (min_width) xml.attribute("width", min_width);
|
||||
if (min_height) xml.attribute("height", min_height);
|
||||
if (opaque) xml.attribute("opaque", "yes");
|
||||
|
||||
xml.attribute("background", String<20>(background));
|
||||
|
||||
xml.node("report", [&] () {
|
||||
xml.attribute("hover", "yes"); });
|
||||
|
||||
@ -308,15 +290,15 @@ void Sandboxed_runtime::View::Menu_view_state::gen_start_node(Xml_generator &xml
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
views.for_each([&] (View const &view) {
|
||||
view._gen_menu_view_dialog(xml); });
|
||||
});
|
||||
|
||||
xml.node("route", [&] () {
|
||||
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "ROM");
|
||||
xml.attribute("label", "dialog");
|
||||
xml.node("local", [&] () { });
|
||||
});
|
||||
views.for_each([&] (View const &view) {
|
||||
view._gen_menu_view_routes(xml); });
|
||||
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "Report");
|
||||
@ -336,44 +318,118 @@ void Sandboxed_runtime::View::Menu_view_state::gen_start_node(Xml_generator &xml
|
||||
xml.attribute("label", "fonts"); });
|
||||
});
|
||||
|
||||
xml.node("any-service", [&] () {
|
||||
xml.node("parent", [&] () { }); });
|
||||
auto parent_route = [&] (auto const &service)
|
||||
{
|
||||
xml.node("service", [&] {
|
||||
xml.attribute("name", service);
|
||||
xml.node("parent", [&] { }); });
|
||||
};
|
||||
|
||||
parent_route("PD");
|
||||
parent_route("CPU");
|
||||
parent_route("LOG");
|
||||
parent_route("Timer");
|
||||
|
||||
auto parent_rom_route = [&] (auto const &name)
|
||||
{
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "ROM");
|
||||
xml.attribute("label_last", name);
|
||||
xml.node("parent", [&] { }); });
|
||||
};
|
||||
|
||||
parent_rom_route("menu_view");
|
||||
parent_rom_route("ld.lib.so");
|
||||
parent_rom_route("libc.lib.so");
|
||||
parent_rom_route("libm.lib.so");
|
||||
parent_rom_route("libpng.lib.so");
|
||||
parent_rom_route("zlib.lib.so");
|
||||
parent_rom_route("vfs.lib.so");
|
||||
parent_rom_route("menu_view_styles.tar");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::View::_gen_menu_view_dialog(Xml_generator &xml) const
|
||||
{
|
||||
xml.node("dialog", [&] {
|
||||
xml.attribute("name", name);
|
||||
|
||||
if (xpos) xml.attribute("xpos", xpos);
|
||||
if (ypos) xml.attribute("ypos", ypos);
|
||||
if (min_width) xml.attribute("width", min_width);
|
||||
if (min_height) xml.attribute("height", min_height);
|
||||
if (opaque) xml.attribute("opaque", "yes");
|
||||
|
||||
xml.attribute("background", String<20>(background));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::View::_gen_menu_view_routes(Xml_generator &xml) const
|
||||
{
|
||||
xml.node("service", [&] {
|
||||
xml.attribute("name", "ROM");
|
||||
xml.attribute("label", name);
|
||||
xml.node("local", [&] { });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::View::_handle_input_event(Input::Event const &event)
|
||||
{
|
||||
if (event.absolute_motion()) _hover_observable_without_click = true;
|
||||
if (event.touch()) _hover_observable_without_click = false;
|
||||
|
||||
Event::Seq_number const global_seq = _runtime._global_seq_number;
|
||||
|
||||
if (click(event) && !_click_seq_number.constructed()) {
|
||||
_click_seq_number.construct(_global_seq_number);
|
||||
_click_seq_number.construct(global_seq);
|
||||
_click_delivered = false;
|
||||
}
|
||||
|
||||
if (clack(event))
|
||||
_clack_seq_number.construct(_global_seq_number);
|
||||
_clack_seq_number.construct(global_seq);
|
||||
|
||||
_try_handle_click_and_clack();
|
||||
|
||||
_optional_event_handler.handle_event(Event { _global_seq_number, event });
|
||||
_runtime._optional_event_handler.handle_event(Event { global_seq, event });
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::_handle_hover()
|
||||
{
|
||||
if (!_hover_report_session.constructed())
|
||||
return;
|
||||
|
||||
using Name = Top_level_dialog::Name;
|
||||
Name const orig_hovered_dialog = _hovered_dialog;
|
||||
|
||||
_hover_report_session->with_xml([&] (Xml_node const &hover) {
|
||||
_hover_seq_number = { hover.attribute_value("seq_number", 0U) };
|
||||
|
||||
hover.with_sub_node("dialog",
|
||||
[&] (Xml_node const &dialog) {
|
||||
_hovered_dialog = dialog.attribute_value("name", Name()); },
|
||||
[&] { _hovered_dialog = { }; });
|
||||
});
|
||||
|
||||
if (orig_hovered_dialog.valid() && orig_hovered_dialog != _hovered_dialog)
|
||||
_views.with_element(orig_hovered_dialog,
|
||||
[&] (View &view) { view._leave(); },
|
||||
[&] { });
|
||||
|
||||
if (_hovered_dialog.valid())
|
||||
_views.with_element(_hovered_dialog,
|
||||
[&] (View &view) { view._handle_hover(); },
|
||||
[&] { });
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::View::_handle_hover()
|
||||
{
|
||||
bool const orig_dialog_hovered = _dialog_hovered;
|
||||
|
||||
if (_hover_report_session.constructed())
|
||||
_hover_report_session->with_xml([&] (Xml_node const &hover) {
|
||||
_hover_seq_number = { hover.attribute_value("seq_number", 0U) };
|
||||
_dialog_hovered = (hover.num_sub_nodes() > 0);
|
||||
});
|
||||
|
||||
if (orig_dialog_hovered != _dialog_hovered || _dialog_hovered)
|
||||
_dialog_rom_session.trigger_update();
|
||||
_dialog_hovered = true;
|
||||
|
||||
if (_click_delivered && _click_seq_number.constructed()) {
|
||||
_with_dialog_hover([&] (Xml_node const &hover) {
|
||||
@ -382,16 +438,24 @@ void Sandboxed_runtime::View::_handle_hover()
|
||||
});
|
||||
}
|
||||
|
||||
_dialog_rom_session.trigger_update();
|
||||
_try_handle_click_and_clack();
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::View::_leave()
|
||||
{
|
||||
_dialog_hovered = false;
|
||||
_dialog_rom_session.trigger_update();
|
||||
}
|
||||
|
||||
|
||||
void Sandboxed_runtime::View::_try_handle_click_and_clack()
|
||||
{
|
||||
Constructible<Event::Seq_number> &click = _click_seq_number,
|
||||
&clack = _clack_seq_number;
|
||||
|
||||
if (!_click_delivered && click.constructed() && *click == _hover_seq_number) {
|
||||
if (!_click_delivered && click.constructed() && *click == _runtime._hover_seq_number) {
|
||||
_with_dialog_hover([&] (Xml_node const &hover) {
|
||||
Clicked_at at(*click, hover);
|
||||
_dialog.click(at);
|
||||
@ -399,7 +463,7 @@ void Sandboxed_runtime::View::_try_handle_click_and_clack()
|
||||
});
|
||||
}
|
||||
|
||||
if (click.constructed() && clack.constructed() && *clack== _hover_seq_number) {
|
||||
if (click.constructed() && clack.constructed() && *clack == _runtime._hover_seq_number) {
|
||||
_with_dialog_hover([&] (Xml_node const &hover) {
|
||||
/* use click seq number for to associate clack with click */
|
||||
Clacked_at at(*click, hover);
|
||||
@ -415,5 +479,5 @@ void Sandboxed_runtime::View::_try_handle_click_and_clack()
|
||||
Sandboxed_runtime::View::~View()
|
||||
{
|
||||
_gui_sessions.for_each([&] (Gui_session &session) {
|
||||
destroy(_alloc, &session); });
|
||||
destroy(_runtime._alloc, &session); });
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user