mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
parent
9144d47fe2
commit
769a6ce987
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* \brief Runtime state of a child hosted in the runtime subsystem
|
||||
* \author Norman Feske
|
||||
* \date 2018-09-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CHILD_STATE_H_
|
||||
#define _CHILD_STATE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/xml_node.h>
|
||||
#include <util/noncopyable.h>
|
||||
#include <util/string.h>
|
||||
#include <base/registry.h>
|
||||
#include <base/quota_guard.h>
|
||||
|
||||
/* local includes */
|
||||
#include "types.h"
|
||||
|
||||
namespace Touch_keyboard { struct Child_state; }
|
||||
|
||||
struct Touch_keyboard::Child_state : Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
using Start_name = String<128>;
|
||||
|
||||
Registry<Child_state>::Element _element;
|
||||
|
||||
Start_name const _name;
|
||||
|
||||
Ram_quota const _initial_ram_quota;
|
||||
Cap_quota const _initial_cap_quota;
|
||||
|
||||
Ram_quota _ram_quota = _initial_ram_quota;
|
||||
Cap_quota _cap_quota = _initial_cap_quota;
|
||||
|
||||
struct Version { unsigned value; } _version { 0 };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ram_quota initial RAM quota
|
||||
* \param cap_quota initial capability quota
|
||||
*/
|
||||
Child_state(Registry<Child_state> ®istry, Start_name const &name,
|
||||
Ram_quota ram_quota, Cap_quota cap_quota)
|
||||
:
|
||||
_element(registry, *this),
|
||||
_name(name),
|
||||
_initial_ram_quota(ram_quota), _initial_cap_quota(cap_quota)
|
||||
{ }
|
||||
|
||||
void trigger_restart()
|
||||
{
|
||||
_version.value++;
|
||||
_ram_quota = _initial_ram_quota;
|
||||
_cap_quota = _initial_cap_quota;
|
||||
}
|
||||
|
||||
void gen_start_node_version(Xml_generator &xml) const
|
||||
{
|
||||
if (_version.value)
|
||||
xml.attribute("version", _version.value);
|
||||
}
|
||||
|
||||
void gen_start_node_content(Xml_generator &xml) const
|
||||
{
|
||||
xml.attribute("name", _name);
|
||||
|
||||
gen_start_node_version(xml);
|
||||
|
||||
xml.attribute("caps", _cap_quota.value);
|
||||
xml.node("resource", [&] () {
|
||||
xml.attribute("name", "RAM");
|
||||
Number_of_bytes const bytes(_ram_quota.value);
|
||||
xml.attribute("quantum", String<64>(bytes)); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt runtime state information to the child
|
||||
*
|
||||
* This method responds to RAM and cap-resource requests by increasing
|
||||
* the resource quotas as needed.
|
||||
*
|
||||
* \param child child node of the runtime'r state report
|
||||
* \return true if runtime must be reconfigured so that the changes
|
||||
* can take effect
|
||||
*/
|
||||
bool apply_child_state_report(Xml_node child)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (child.attribute_value("name", Start_name()) != _name)
|
||||
return false;
|
||||
|
||||
if (child.has_sub_node("ram") && child.sub_node("ram").has_attribute("requested")) {
|
||||
_ram_quota.value *= 2;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (child.has_sub_node("caps") && child.sub_node("caps").has_attribute("requested")) {
|
||||
_cap_quota.value += 100;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Ram_quota ram_quota() const { return _ram_quota; }
|
||||
|
||||
Start_name name() const { return _name; }
|
||||
};
|
||||
|
||||
#endif /* _CHILD_STATE_H_ */
|
@ -1,141 +0,0 @@
|
||||
/*
|
||||
* \brief GUI wrapper for monitoring the user input of GUI components
|
||||
* \author Norman Feske
|
||||
* \date 2020-01-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _GUI_H_
|
||||
#define _GUI_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <input/component.h>
|
||||
#include <base/session_object.h>
|
||||
#include <gui_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <input_event_handler.h>
|
||||
|
||||
namespace Gui {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
struct Session_component;
|
||||
}
|
||||
|
||||
|
||||
struct Gui::Session_component : Session_object<Gui::Session>
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
Input_event_handler &_event_handler;
|
||||
|
||||
Input::Seq_number &_global_seq_number;
|
||||
|
||||
Gui::Connection _connection;
|
||||
|
||||
Input::Session_component _input_component { _env, _env.ram() };
|
||||
|
||||
Signal_handler<Session_component> _input_handler {
|
||||
_env.ep(), *this, &Session_component::_handle_input };
|
||||
|
||||
void _handle_input()
|
||||
{
|
||||
_connection.input()->for_each_event([&] (Input::Event ev) {
|
||||
|
||||
/*
|
||||
* Augment input stream with sequence numbers to correlate
|
||||
* clicks with hover reports.
|
||||
*/
|
||||
if (ev.touch() || ev.touch_release()) {
|
||||
_global_seq_number.value++;
|
||||
_input_component.submit(_global_seq_number);
|
||||
}
|
||||
|
||||
/*
|
||||
* Feed touch coordinates of primary finger as absolute motion to
|
||||
* the menu view to trigger an update of the hover report.
|
||||
*/
|
||||
ev.handle_touch([&] (Input::Touch_id id, float x, float y) {
|
||||
Input::Absolute_motion const xy { (int)x, (int)y };
|
||||
if (id.value == 0)
|
||||
_input_component.submit(xy); });
|
||||
|
||||
_event_handler.handle_input_event(ev);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename... ARGS>
|
||||
Session_component(Env &env, Input_event_handler &event_handler,
|
||||
Input::Seq_number &global_seq_number, ARGS &&... args)
|
||||
:
|
||||
Session_object(args...),
|
||||
_env(env), _event_handler(event_handler),
|
||||
_global_seq_number(global_seq_number),
|
||||
_connection(env, _label.string())
|
||||
{
|
||||
_connection.input()->sigh(_input_handler);
|
||||
_env.ep().manage(_input_component);
|
||||
_input_component.event_queue().enabled(true);
|
||||
}
|
||||
|
||||
~Session_component() { _env.ep().dissolve(_input_component); }
|
||||
|
||||
void upgrade(Session::Resources const &resources)
|
||||
{
|
||||
_connection.upgrade(resources);
|
||||
}
|
||||
|
||||
Framebuffer::Session_capability framebuffer_session() override {
|
||||
return _connection.framebuffer_session(); }
|
||||
|
||||
Input::Session_capability input_session() override {
|
||||
return _input_component.cap(); }
|
||||
|
||||
View_handle create_view(View_handle parent) override {
|
||||
return _connection.create_view(parent); }
|
||||
|
||||
void destroy_view(View_handle view) override {
|
||||
_connection.destroy_view(view); }
|
||||
|
||||
View_handle view_handle(View_capability view_cap, View_handle handle) override {
|
||||
return _connection.view_handle(view_cap, handle); }
|
||||
|
||||
View_capability view_capability(View_handle view) override {
|
||||
return _connection.view_capability(view); }
|
||||
|
||||
void release_view_handle(View_handle view) override {
|
||||
_connection.release_view_handle(view); }
|
||||
|
||||
Dataspace_capability command_dataspace() override {
|
||||
return _connection.command_dataspace(); }
|
||||
|
||||
void execute() override {
|
||||
_connection.execute(); }
|
||||
|
||||
Framebuffer::Mode mode() override {
|
||||
return _connection.mode(); }
|
||||
|
||||
void mode_sigh(Signal_context_capability sigh) override {
|
||||
_connection.mode_sigh(sigh); }
|
||||
|
||||
void buffer(Framebuffer::Mode mode, bool use_alpha) override
|
||||
{
|
||||
/*
|
||||
* Do not call 'Connection::buffer' to avoid paying session quota
|
||||
* from our own budget.
|
||||
*/
|
||||
_connection.Client::buffer(mode, use_alpha);
|
||||
}
|
||||
|
||||
void focus(Capability<Gui::Session> session) override {
|
||||
_connection.focus(session); }
|
||||
};
|
||||
|
||||
#endif /* _GUI_H_ */
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* \brief Interface for handling input events
|
||||
* \author Norman Feske
|
||||
* \date 2018-05-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _INPUT_EVENT_HANDLER_H_
|
||||
#define _INPUT_EVENT_HANDLER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/interface.h>
|
||||
#include <input/event.h>
|
||||
|
||||
namespace Gui { struct Input_event_handler; }
|
||||
|
||||
struct Gui::Input_event_handler : Genode::Interface
|
||||
{
|
||||
virtual void handle_input_event(Input::Event const &) = 0;
|
||||
};
|
||||
|
||||
#endif /* _INPUT_EVENT_HANDLER_H_ */
|
@ -13,26 +13,23 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/session_object.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <sandbox/sandbox.h>
|
||||
#include <os/dynamic_rom_session.h>
|
||||
#include <os/reporter.h>
|
||||
#include <os/buffered_xml.h>
|
||||
#include <event_session/connection.h>
|
||||
#include <dialog/runtime.h>
|
||||
#include <util/color.h>
|
||||
|
||||
/* local includes */
|
||||
#include <gui.h>
|
||||
#include <report.h>
|
||||
#include <touch_keyboard_dialog.h>
|
||||
#include <child_state.h>
|
||||
#include <touch_keyboard_widget.h>
|
||||
|
||||
namespace Touch_keyboard { struct Main; }
|
||||
namespace Touch_keyboard {
|
||||
|
||||
struct Touch_keyboard::Main : Sandbox::Local_service_base::Wakeup,
|
||||
Sandbox::State_handler,
|
||||
Gui::Input_event_handler,
|
||||
Dialog::Event_emitter
|
||||
using namespace Dialog;
|
||||
|
||||
struct Main;
|
||||
}
|
||||
|
||||
|
||||
struct Touch_keyboard::Main : Top_level_dialog
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
@ -41,238 +38,43 @@ struct Touch_keyboard::Main : Sandbox::Local_service_base::Wakeup,
|
||||
Attached_rom_dataspace _config { _env, "config" };
|
||||
Attached_rom_dataspace _layout { _env, "layout" };
|
||||
|
||||
int _xpos = 0;
|
||||
int _ypos = 0;
|
||||
unsigned _min_width = 0;
|
||||
unsigned _min_height = 0;
|
||||
|
||||
bool _opaque = false;
|
||||
Color _background { };
|
||||
|
||||
Registry<Child_state> _children { };
|
||||
|
||||
Child_state _menu_view_child_state { _children, "menu_view",
|
||||
Ram_quota { 10*1024*1024 },
|
||||
Cap_quota { 200 } };
|
||||
/**
|
||||
* Sandbox::State_handler
|
||||
*/
|
||||
void handle_sandbox_state() override
|
||||
{
|
||||
/* obtain current sandbox state */
|
||||
Buffered_xml state(_heap, "state", [&] (Xml_generator &xml) {
|
||||
_sandbox.generate_state_report(xml);
|
||||
});
|
||||
|
||||
bool reconfiguration_needed = false;
|
||||
|
||||
state.with_xml_node([&] (Xml_node state) {
|
||||
state.for_each_sub_node("child", [&] (Xml_node const &child) {
|
||||
if (_menu_view_child_state.apply_child_state_report(child))
|
||||
reconfiguration_needed = true; }); });
|
||||
|
||||
if (reconfiguration_needed)
|
||||
_update_sandbox_config();
|
||||
}
|
||||
|
||||
Sandbox _sandbox { _env, *this };
|
||||
|
||||
typedef Sandbox::Local_service<Gui::Session_component> Gui_service;
|
||||
|
||||
Gui_service _gui_service { _sandbox, *this };
|
||||
|
||||
typedef Sandbox::Local_service<Dynamic_rom_session> Rom_service;
|
||||
|
||||
Rom_service _rom_service { _sandbox, *this };
|
||||
|
||||
typedef Sandbox::Local_service<Report::Session_component> Report_service;
|
||||
|
||||
Report_service _report_service { _sandbox, *this };
|
||||
|
||||
void _handle_hover(Xml_node const &node)
|
||||
{
|
||||
Input::Seq_number hover_seq { node.attribute_value("seq_number", 0U) };
|
||||
|
||||
node.with_optional_sub_node("dialog", [&] (Xml_node const &dialog) {
|
||||
_dialog.handle_hover(hover_seq, dialog); });
|
||||
}
|
||||
|
||||
Report::Session_component::Xml_handler<Main>
|
||||
_hover_handler { *this, &Main::_handle_hover };
|
||||
|
||||
Dialog _dialog { _env.ep(), _env.ram(), _env.rm(), _heap, *this };
|
||||
|
||||
void _generate_sandbox_config(Xml_generator &xml) const
|
||||
{
|
||||
xml.node("report", [&] () {
|
||||
xml.attribute("child_ram", "yes");
|
||||
xml.attribute("child_caps", "yes");
|
||||
xml.attribute("delay_ms", 20*1000);
|
||||
});
|
||||
xml.node("parent-provides", [&] () {
|
||||
|
||||
auto service_node = [&] (char const *name) {
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", name); }); };
|
||||
|
||||
service_node("ROM");
|
||||
service_node("CPU");
|
||||
service_node("PD");
|
||||
service_node("LOG");
|
||||
service_node("File_system");
|
||||
service_node("Gui");
|
||||
service_node("Timer");
|
||||
service_node("Report");
|
||||
});
|
||||
|
||||
xml.node("start", [&] () {
|
||||
_menu_view_child_state.gen_start_node_content(xml);
|
||||
|
||||
xml.node("config", [&] () {
|
||||
xml.attribute("xpos", _xpos);
|
||||
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"); });
|
||||
|
||||
xml.node("libc", [&] () {
|
||||
xml.attribute("stderr", "/dev/log"); });
|
||||
|
||||
xml.node("vfs", [&] () {
|
||||
xml.node("tar", [&] () {
|
||||
xml.attribute("name", "menu_view_styles.tar"); });
|
||||
xml.node("dir", [&] () {
|
||||
xml.attribute("name", "dev");
|
||||
xml.node("log", [&] () { });
|
||||
});
|
||||
xml.node("dir", [&] () {
|
||||
xml.attribute("name", "fonts");
|
||||
xml.node("fs", [&] () {
|
||||
xml.attribute("label", "fonts");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
xml.node("route", [&] () {
|
||||
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "ROM");
|
||||
xml.attribute("label", "dialog");
|
||||
xml.node("local", [&] () { });
|
||||
});
|
||||
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "Report");
|
||||
xml.attribute("label", "hover");
|
||||
xml.node("local", [&] () { });
|
||||
});
|
||||
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "Gui");
|
||||
xml.node("local", [&] () { });
|
||||
});
|
||||
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "File_system");
|
||||
xml.attribute("label", "fonts");
|
||||
xml.node("parent", [&] () {
|
||||
xml.attribute("label", "fonts"); });
|
||||
});
|
||||
|
||||
xml.node("any-service", [&] () {
|
||||
xml.node("parent", [&] () { }); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sandbox::Local_service_base::Wakeup interface
|
||||
*/
|
||||
void wakeup_local_service() override
|
||||
{
|
||||
_rom_service.for_each_requested_session([&] (Rom_service::Request &request) {
|
||||
|
||||
if (request.label == "menu_view -> dialog")
|
||||
request.deliver_session(_dialog.rom_session);
|
||||
else
|
||||
request.deny();
|
||||
});
|
||||
|
||||
_report_service.for_each_requested_session([&] (Report_service::Request &request) {
|
||||
|
||||
if (request.label == "menu_view -> hover") {
|
||||
Report::Session_component &session = *new (_heap)
|
||||
Report::Session_component(_env, _hover_handler,
|
||||
_env.ep(),
|
||||
request.resources, "", request.diag);
|
||||
request.deliver_session(session);
|
||||
}
|
||||
});
|
||||
|
||||
_report_service.for_each_session_to_close([&] (Report::Session_component &session) {
|
||||
|
||||
destroy(_heap, &session);
|
||||
return Report_service::Close_response::CLOSED;
|
||||
});
|
||||
|
||||
_gui_service.for_each_requested_session([&] (Gui_service::Request &request) {
|
||||
|
||||
Gui::Session_component &session = *new (_heap)
|
||||
Gui::Session_component(_env, *this, _global_input_seq_number, _env.ep(),
|
||||
request.resources, "", request.diag);
|
||||
|
||||
request.deliver_session(session);
|
||||
});
|
||||
|
||||
_gui_service.for_each_upgraded_session([&] (Gui::Session_component &session,
|
||||
Session::Resources const &amount) {
|
||||
session.upgrade(amount);
|
||||
return Gui_service::Upgrade_response::CONFIRMED;
|
||||
});
|
||||
|
||||
_gui_service.for_each_session_to_close([&] (Gui::Session_component &session) {
|
||||
|
||||
destroy(_heap, &session);
|
||||
return Gui_service::Close_response::CLOSED;
|
||||
});
|
||||
}
|
||||
Hosted<Touch_keyboard_widget> _keyboard { Id { "keyboard" }, _heap };
|
||||
|
||||
Event::Connection _event_connection { _env };
|
||||
|
||||
/**
|
||||
* Dialog::Event_emitter interface
|
||||
Runtime _runtime { _env, _heap };
|
||||
|
||||
Runtime::View _view { _runtime, *this, Runtime::View::Attr {
|
||||
.opaque = true,
|
||||
.initial_ram = Ram_quota { 4*1024*1024 }
|
||||
} };
|
||||
|
||||
/*
|
||||
* Top_level_dialog interface
|
||||
*/
|
||||
void emit_characters(Dialog::Emit const &characters) override
|
||||
|
||||
void view(Scope<> &s) const override { s.widget(_keyboard); }
|
||||
|
||||
void click(Clicked_at const &at) override { _keyboard.propagate(at); }
|
||||
|
||||
void clack(Clacked_at const &at) override
|
||||
{
|
||||
_event_connection.with_batch([&] (Event::Session_client::Batch &batch) {
|
||||
_keyboard.propagate(at, [&] (Touch_keyboard_widget::Emit const &characters) {
|
||||
_event_connection.with_batch([&] (Event::Session_client::Batch &batch) {
|
||||
|
||||
Utf8_ptr utf8_ptr(characters.string());
|
||||
Utf8_ptr utf8_ptr(characters.string());
|
||||
|
||||
for (; utf8_ptr.complete(); utf8_ptr = utf8_ptr.next()) {
|
||||
for (; utf8_ptr.complete(); utf8_ptr = utf8_ptr.next()) {
|
||||
|
||||
Codepoint c = utf8_ptr.codepoint();
|
||||
batch.submit( Input::Press_char { Input::KEY_UNKNOWN, c } );
|
||||
batch.submit( Input::Release { Input::KEY_UNKNOWN } );
|
||||
}
|
||||
Codepoint c = utf8_ptr.codepoint();
|
||||
batch.submit( Input::Press_char { Input::KEY_UNKNOWN, c } );
|
||||
batch.submit( Input::Release { Input::KEY_UNKNOWN } );
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Input::Seq_number _global_input_seq_number { };
|
||||
|
||||
/**
|
||||
* Gui::Input_event_handler interface
|
||||
*/
|
||||
void handle_input_event(Input::Event const &event) override
|
||||
{
|
||||
_dialog.handle_input_event(_global_input_seq_number, event);
|
||||
}
|
||||
void drag (Dragged_at const &) override { }
|
||||
|
||||
void _handle_config()
|
||||
{
|
||||
@ -281,38 +83,28 @@ struct Touch_keyboard::Main : Sandbox::Local_service_base::Wakeup,
|
||||
|
||||
Xml_node const config = _config.xml();
|
||||
|
||||
_xpos = (int)config.attribute_value("xpos", 0L);
|
||||
_ypos = (int)config.attribute_value("ypos", 0L);
|
||||
_view.xpos = (int)config.attribute_value("xpos", 0L);
|
||||
_view.ypos = (int)config.attribute_value("ypos", 0L);
|
||||
|
||||
_min_width = config.attribute_value("min_width", 0U);
|
||||
_min_height = config.attribute_value("min_height", 0U);
|
||||
_view.min_width = config.attribute_value("min_width", 0U);
|
||||
_view.min_height = config.attribute_value("min_height", 0U);
|
||||
|
||||
_opaque = config.attribute_value("opaque", false);
|
||||
_background = config.attribute_value("background", Color(127, 127, 127, 255));
|
||||
_view.opaque = config.attribute_value("opaque", false);
|
||||
_view.background = config.attribute_value("background", Color(127, 127, 127, 255));
|
||||
|
||||
_dialog.configure(_layout.xml());
|
||||
_keyboard.configure(_layout.xml());
|
||||
|
||||
_runtime.update_view_config();
|
||||
}
|
||||
|
||||
Signal_handler<Main> _config_handler {
|
||||
_env.ep(), *this, &Main::_handle_config };
|
||||
|
||||
void _update_sandbox_config()
|
||||
{
|
||||
Buffered_xml const config { _heap, "config", [&] (Xml_generator &xml) {
|
||||
_generate_sandbox_config(xml); } };
|
||||
|
||||
config.with_xml_node([&] (Xml_node const &config) {
|
||||
_sandbox.apply_config(config); });
|
||||
}
|
||||
|
||||
Main(Env &env)
|
||||
:
|
||||
_env(env)
|
||||
Main(Env &env) : Top_level_dialog("touch_keyboard"), _env(env)
|
||||
{
|
||||
_config.sigh(_config_handler);
|
||||
_layout.sigh(_config_handler);
|
||||
_handle_config();
|
||||
_update_sandbox_config();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* \brief Report session provided to the sandbox
|
||||
* \author Norman Feske
|
||||
* \date 2020-01-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _REPORT_H_
|
||||
#define _REPORT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/session_object.h>
|
||||
#include <report_session/report_session.h>
|
||||
|
||||
namespace Report {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
struct Session_component;
|
||||
}
|
||||
|
||||
|
||||
class Report::Session_component : public Session_object<Report::Session>
|
||||
{
|
||||
public:
|
||||
|
||||
struct Handler_base : Interface, Genode::Noncopyable
|
||||
{
|
||||
virtual void handle_report(char const *, size_t) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Xml_handler : Handler_base
|
||||
{
|
||||
T &_obj;
|
||||
void (T::*_member) (Xml_node const &);
|
||||
|
||||
Xml_handler(T &obj, void (T::*member)(Xml_node const &))
|
||||
: _obj(obj), _member(member) { }
|
||||
|
||||
void handle_report(char const *start, size_t length) override
|
||||
{
|
||||
(_obj.*_member)(Xml_node(start, length));
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Attached_ram_dataspace _ds;
|
||||
|
||||
Handler_base &_handler;
|
||||
|
||||
|
||||
/*******************************
|
||||
** Report::Session interface **
|
||||
*******************************/
|
||||
|
||||
Dataspace_capability dataspace() override { return _ds.cap(); }
|
||||
|
||||
void submit(size_t length) override
|
||||
{
|
||||
_handler.handle_report(_ds.local_addr<char const>(),
|
||||
min(_ds.size(), length));
|
||||
}
|
||||
|
||||
void response_sigh(Signal_context_capability) override { }
|
||||
|
||||
size_t obtain_response() override { return 0; }
|
||||
|
||||
public:
|
||||
|
||||
template <typename... ARGS>
|
||||
Session_component(Env &env, Handler_base &handler,
|
||||
Entrypoint &ep, Resources const &resources,
|
||||
ARGS &&... args)
|
||||
:
|
||||
Session_object(ep, resources, args...),
|
||||
_ds(env.ram(), env.rm(), resources.ram_quota.value),
|
||||
_handler(handler)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _REPORT_H_ */
|
@ -1,4 +1,4 @@
|
||||
TARGET = touch_keyboard
|
||||
SRC_CC = main.cc touch_keyboard_dialog.cc
|
||||
LIBS += base sandbox
|
||||
SRC_CC = main.cc touch_keyboard_widget.cc
|
||||
LIBS += base sandbox dialog
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* \brief Touch-screen keyboard dialog
|
||||
* \author Norman Feske
|
||||
* \date 2022-01-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* local includes */
|
||||
#include <touch_keyboard_dialog.h>
|
||||
|
||||
using namespace Touch_keyboard;
|
||||
|
||||
|
||||
void Dialog::produce_xml(Xml_generator &xml)
|
||||
{
|
||||
auto gen_key = [&] (Key const &key)
|
||||
{
|
||||
xml.node("vbox", [&] () {
|
||||
xml.attribute("name", key._id);
|
||||
|
||||
xml.node("button", [&] () {
|
||||
bool const selected = (_emit_on_release.length() > 1)
|
||||
&& (key.emit == _emit_on_release);
|
||||
if (selected)
|
||||
xml.attribute("selected", "yes");
|
||||
|
||||
if (key.map.length() > 1)
|
||||
xml.attribute("style", "unimportant");
|
||||
|
||||
if (key.label.length() == 1)
|
||||
xml.attribute("style", "invisible");
|
||||
|
||||
xml.node("vbox", [&] () {
|
||||
xml.node("label", [&] () {
|
||||
xml.attribute("name", "spacer");
|
||||
unsigned const min_ex = key.min_ex
|
||||
? key.min_ex
|
||||
: _default_key_min_ex;
|
||||
if (min_ex)
|
||||
xml.attribute("min_ex", min_ex);
|
||||
});
|
||||
xml.node("label", [&] () {
|
||||
xml.attribute("name", "label");
|
||||
xml.attribute("text", key.label);
|
||||
if (key.small)
|
||||
xml.attribute("font", "annotation/regular");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
auto gen_row = [&] (Row const &row)
|
||||
{
|
||||
xml.node("hbox", [&] () {
|
||||
xml.attribute("name", row._id);
|
||||
row.keys.for_each([&] (Key const &key) {
|
||||
gen_key(key); }); });
|
||||
};
|
||||
|
||||
auto gen_map = [&] (Map const &map)
|
||||
{
|
||||
if (map.name != _current_map)
|
||||
return;
|
||||
|
||||
xml.node("vbox", [&] () {
|
||||
map.rows.for_each([&] (Row const &row) {
|
||||
gen_row(row); }); });
|
||||
};
|
||||
|
||||
_maps.for_each([&] (Map const &map) {
|
||||
gen_map(map); });
|
||||
}
|
||||
|
||||
|
||||
void Dialog::handle_input_event(Input::Seq_number curr_seq, Input::Event const &event)
|
||||
{
|
||||
if (event.touch())
|
||||
_clicked_seq_number.construct(curr_seq);
|
||||
|
||||
if (_emit_on_release.length() > 1 && event.touch_release()) {
|
||||
_event_emitter.emit_characters(_emit_on_release);
|
||||
_emit_on_release = { };
|
||||
rom_session.trigger_update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Dialog::handle_hover(Input::Seq_number seq, Xml_node const &dialog)
|
||||
{
|
||||
Row::Id hovered_row_id { };
|
||||
Key::Id hovered_key_id { };
|
||||
|
||||
dialog.with_optional_sub_node("vbox", [&] (Xml_node const &vbox) {
|
||||
vbox.with_optional_sub_node("hbox", [&] (Xml_node const &hbox) {
|
||||
hbox.with_optional_sub_node("vbox", [&] (Xml_node const &button) {
|
||||
hovered_row_id = hbox .attribute_value("name", Row::Id());
|
||||
hovered_key_id = button.attribute_value("name", Key::Id());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
_maps.for_each([&] (Map const &map) {
|
||||
if (map.name != _current_map)
|
||||
return;
|
||||
|
||||
map.rows.for_each([&] (Row const &row) {
|
||||
if (row._id != hovered_row_id)
|
||||
return;
|
||||
|
||||
row.keys.for_each([&] (Key const &key) {
|
||||
if (key._id != hovered_key_id)
|
||||
return;
|
||||
|
||||
if (_clicked_seq_number.constructed()) {
|
||||
if (seq.value >= _clicked_seq_number->value) {
|
||||
_emit_on_release = key.emit;
|
||||
_clicked_seq_number.destruct();
|
||||
|
||||
if (key.map.length() > 1)
|
||||
_current_map = key.map;
|
||||
|
||||
rom_session.trigger_update();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Dialog::Dialog(Entrypoint &ep, Ram_allocator &ram, Region_map &rm,
|
||||
Allocator &alloc, Event_emitter &event_emitter)
|
||||
:
|
||||
Xml_producer("dialog"),
|
||||
rom_session(ep, ram, rm, *this),
|
||||
_alloc(alloc), _event_emitter(event_emitter)
|
||||
{ }
|
@ -1,208 +0,0 @@
|
||||
/*
|
||||
* \brief Touch-screen keyboard dialog
|
||||
* \author Norman Feske
|
||||
* \date 2022-01-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _TOUCH_KEYBOARD_DIALOG_H_
|
||||
#define _TOUCH_KEYBOARD_DIALOG_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list_model.h>
|
||||
#include <base/component.h>
|
||||
#include <base/session_object.h>
|
||||
#include <sandbox/sandbox.h>
|
||||
#include <os/dynamic_rom_session.h>
|
||||
#include <input/event.h>
|
||||
|
||||
/* local includes */
|
||||
#include <report.h>
|
||||
#include <types.h>
|
||||
|
||||
namespace Touch_keyboard { struct Dialog; }
|
||||
|
||||
|
||||
struct Touch_keyboard::Dialog : private Dynamic_rom_session::Xml_producer
|
||||
{
|
||||
public:
|
||||
|
||||
Dynamic_rom_session rom_session;
|
||||
|
||||
using Emit = String<8>;
|
||||
|
||||
struct Event_emitter : Interface
|
||||
{
|
||||
virtual void emit_characters(Emit const &) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
Event_emitter &_event_emitter;
|
||||
|
||||
unsigned _default_key_min_ex = 0;
|
||||
|
||||
struct Key : List_model<Key>::Element
|
||||
{
|
||||
using Id = String<8>;
|
||||
Id const _id;
|
||||
|
||||
static Id id_attr(Xml_node const &node) {
|
||||
return node.attribute_value("id", Id()); }
|
||||
|
||||
using Label = String<8>;
|
||||
Label label { };
|
||||
|
||||
Emit emit { };
|
||||
|
||||
using Map = String<8>;
|
||||
Map map { };
|
||||
|
||||
unsigned min_ex = 0;
|
||||
|
||||
bool small = false;
|
||||
|
||||
Key(Id id) : _id(id) { }
|
||||
|
||||
bool matches(Xml_node const &node) const { return _id == id_attr(node); }
|
||||
|
||||
static bool type_matches(Xml_node const &node) { return node.type() == "key"; }
|
||||
|
||||
void update(Xml_node const &key) {
|
||||
|
||||
label = { };
|
||||
emit = { };
|
||||
map = key.attribute_value("map", Map());
|
||||
min_ex = key.attribute_value("min_ex", 0U);
|
||||
small = key.attribute_value("small", false);
|
||||
|
||||
if (key.has_attribute("char")) {
|
||||
label = key.attribute_value("char", Label());
|
||||
emit = Emit(Xml_unquoted(label));
|
||||
}
|
||||
|
||||
if (key.has_attribute("code")) {
|
||||
Codepoint c { key.attribute_value("code", 0U) };
|
||||
emit = Emit(c);
|
||||
label = emit;
|
||||
}
|
||||
|
||||
if (key.has_attribute("label"))
|
||||
label = key.attribute_value("label", Label());
|
||||
}
|
||||
};
|
||||
|
||||
struct Row : List_model<Row>::Element
|
||||
{
|
||||
Allocator &_alloc;
|
||||
|
||||
using Id = String<8>;
|
||||
Id const _id;
|
||||
|
||||
static Id id_attr(Xml_node const &node) {
|
||||
return node.attribute_value("id", Id()); }
|
||||
|
||||
List_model<Key> keys { };
|
||||
|
||||
Row(Allocator &alloc, Id id) : _alloc(alloc), _id(id) { }
|
||||
|
||||
bool matches(Xml_node const &node) const { return _id == id_attr(node); }
|
||||
|
||||
static bool type_matches(Xml_node const &node) { return node.type() == "row"; }
|
||||
|
||||
void update(Xml_node const &row)
|
||||
{
|
||||
keys.update_from_xml(row,
|
||||
|
||||
/* create */
|
||||
[&] (Xml_node const &node) -> Key & {
|
||||
return *new (_alloc) Key(Key::id_attr(node)); },
|
||||
|
||||
/* destroy */
|
||||
[&] (Key &key) { destroy(_alloc, &key); },
|
||||
|
||||
/* update */
|
||||
[&] (Key &key, Xml_node const &node) { key.update(node); });
|
||||
}
|
||||
};
|
||||
|
||||
struct Map : List_model<Map>::Element
|
||||
{
|
||||
Allocator &_alloc;
|
||||
|
||||
using Name = String<16>;
|
||||
Name const name;
|
||||
|
||||
static Name name_attr(Xml_node const &node) {
|
||||
return node.attribute_value("name", Name()); }
|
||||
|
||||
List_model<Row> rows { };
|
||||
|
||||
Map(Allocator &alloc, Name name) : _alloc(alloc), name(name) { }
|
||||
|
||||
bool matches(Xml_node const &node) const { return name == name_attr(node); }
|
||||
|
||||
static bool type_matches(Xml_node const &node) { return node.type() == "map"; }
|
||||
|
||||
void update(Xml_node const &map)
|
||||
{
|
||||
rows.update_from_xml(map,
|
||||
|
||||
/* create */
|
||||
[&] (Xml_node const &node) -> Row & {
|
||||
return *new (_alloc) Row(_alloc, Row::id_attr(node)); },
|
||||
|
||||
/* destroy */
|
||||
[&] (Row &row) { destroy(_alloc, &row); },
|
||||
|
||||
/* update */
|
||||
[&] (Row &row, Xml_node const &node) { row.update(node); });
|
||||
}
|
||||
};
|
||||
|
||||
List_model<Map> _maps { };
|
||||
|
||||
Map::Name _current_map = "lower";
|
||||
|
||||
Constructible<Input::Seq_number> _clicked_seq_number { };
|
||||
|
||||
Emit _emit_on_release { };
|
||||
|
||||
void produce_xml(Xml_generator &xml) override;
|
||||
|
||||
public:
|
||||
|
||||
Dialog(Entrypoint &, Ram_allocator &, Region_map &, Allocator &,
|
||||
Event_emitter &);
|
||||
|
||||
void configure(Xml_node const &config)
|
||||
{
|
||||
_default_key_min_ex = config.attribute_value("key_min_ex", 0U);
|
||||
|
||||
_maps.update_from_xml(config,
|
||||
|
||||
/* create */
|
||||
[&] (Xml_node const &node) -> Map & {
|
||||
return *new (_alloc) Map(_alloc, Map::name_attr(node)); },
|
||||
|
||||
/* destroy */
|
||||
[&] (Map &map) { destroy(_alloc, &map); },
|
||||
|
||||
/* update */
|
||||
[&] (Map &map, Xml_node const &node) { map.update(node); });
|
||||
}
|
||||
|
||||
void handle_input_event(Input::Seq_number curr_seq, Input::Event const &);
|
||||
|
||||
void handle_hover(Input::Seq_number, Xml_node const &hover);
|
||||
};
|
||||
|
||||
#endif /* _TOUCH_KEYBOARD_DIALOG_H_ */
|
77
repos/gems/src/app/touch_keyboard/touch_keyboard_widget.cc
Normal file
77
repos/gems/src/app/touch_keyboard/touch_keyboard_widget.cc
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* \brief Touch-screen keyboard widget
|
||||
* \author Norman Feske
|
||||
* \date 2022-01-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <touch_keyboard_widget.h>
|
||||
|
||||
using namespace Dialog;
|
||||
|
||||
|
||||
void Touch_keyboard_widget::Key::view(Scope<Vbox> &s, Attr const &attr) const
|
||||
{
|
||||
s.widget(_button, [&] (Scope<Button> &s) {
|
||||
|
||||
if (map.length() > 1)
|
||||
s.attribute("style", "unimportant");
|
||||
|
||||
if (text.length() == 1)
|
||||
s.attribute("style", "invisible");
|
||||
|
||||
s.sub_scope<Vbox>([&] (Scope<Button, Vbox> &s) {
|
||||
|
||||
unsigned const ex = min_ex ? min_ex : attr.default_key_min_ex.value;
|
||||
if (ex)
|
||||
s.sub_scope<Min_ex>(ex);
|
||||
|
||||
s.sub_scope<Label>(text, [&] (auto &s) {
|
||||
if (small)
|
||||
s.attribute("font", "annotation/regular"); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Touch_keyboard_widget::Row::view(Scope<Hbox> &s, Attr const &attr) const
|
||||
{
|
||||
keys.for_each([&] (Hosted_key const &key) {
|
||||
s.widget(key, Key::Attr {
|
||||
.default_key_min_ex = attr.default_key_min_ex }); });
|
||||
}
|
||||
|
||||
|
||||
void Touch_keyboard_widget::view(Scope<Vbox> &s) const
|
||||
{
|
||||
_with_current_map(*this, [&] (Map const &map) {
|
||||
map.rows.for_each([&] (Map::Hosted_row const &row) {
|
||||
s.widget(row, Row::Attr {
|
||||
.default_key_min_ex = _default_key_min_ex }); }); });
|
||||
}
|
||||
|
||||
|
||||
void Touch_keyboard_widget::click(Clicked_at const &at)
|
||||
{
|
||||
Key::Map next_map = _current_map;
|
||||
|
||||
_with_current_map(*this, [&] (Map &map) {
|
||||
map.rows.for_each([&] (Map::Hosted_row &row) {
|
||||
row.propagate(at, [&] (Key &key) {
|
||||
|
||||
_emit_on_clack = key.emit;
|
||||
|
||||
if (key.map.length() > 1)
|
||||
next_map = key.map;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
_current_map = next_map;
|
||||
}
|
235
repos/gems/src/app/touch_keyboard/touch_keyboard_widget.h
Normal file
235
repos/gems/src/app/touch_keyboard/touch_keyboard_widget.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* \brief Touch-screen keyboard dialog
|
||||
* \author Norman Feske
|
||||
* \date 2022-01-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _TOUCH_KEYBOARD_DIALOG_H_
|
||||
#define _TOUCH_KEYBOARD_DIALOG_H_
|
||||
|
||||
#include <base/allocator.h>
|
||||
#include <util/list_model.h>
|
||||
#include <dialog/widgets.h>
|
||||
|
||||
namespace Dialog { struct Touch_keyboard_widget; }
|
||||
|
||||
|
||||
struct Dialog::Touch_keyboard_widget : Widget<Vbox>
|
||||
{
|
||||
public:
|
||||
|
||||
using Emit = String<8>;
|
||||
|
||||
private:
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
struct Default_key_min_ex { unsigned value; };
|
||||
|
||||
Default_key_min_ex _default_key_min_ex { 0 };
|
||||
|
||||
static Id _id_attr(Xml_node const &node)
|
||||
{
|
||||
return { node.attribute_value("id", Id::Value { }) };
|
||||
}
|
||||
|
||||
struct Key : Widget<Vbox>
|
||||
{
|
||||
Id const _id;
|
||||
|
||||
using Text = String<8>;
|
||||
Text text { };
|
||||
|
||||
Emit emit { };
|
||||
|
||||
using Map = String<8>;
|
||||
Map map { };
|
||||
|
||||
unsigned min_ex = 0;
|
||||
|
||||
bool small = false;
|
||||
|
||||
Key(Id id) : _id(id) { }
|
||||
|
||||
bool matches(Xml_node const &node) const { return _id == _id_attr(node); }
|
||||
|
||||
static bool type_matches(Xml_node const &node) { return node.type() == "key"; }
|
||||
|
||||
Hosted<Vbox, Action_button> _button { Id { } };
|
||||
|
||||
void update(Xml_node const &key) {
|
||||
|
||||
text = { };
|
||||
emit = { };
|
||||
map = key.attribute_value("map", Map());
|
||||
min_ex = key.attribute_value("min_ex", 0U);
|
||||
small = key.attribute_value("small", false);
|
||||
|
||||
if (key.has_attribute("char")) {
|
||||
text = key.attribute_value("char", Text());
|
||||
emit = Emit(Xml_unquoted(text));
|
||||
}
|
||||
|
||||
if (key.has_attribute("code")) {
|
||||
Codepoint c { key.attribute_value("code", 0U) };
|
||||
emit = Emit(c);
|
||||
text = emit;
|
||||
}
|
||||
|
||||
if (key.has_attribute("label"))
|
||||
text = key.attribute_value("label", Text());
|
||||
}
|
||||
|
||||
struct Attr { Default_key_min_ex default_key_min_ex; };
|
||||
|
||||
void view(Scope<Vbox> &s, Attr const &attr) const;
|
||||
|
||||
void click(Clicked_at const &at, auto const &fn)
|
||||
{
|
||||
_button.propagate(at, [&] { /* drive selected state */ });
|
||||
fn(*this);
|
||||
}
|
||||
};
|
||||
|
||||
struct Row : Widget<Hbox>
|
||||
{
|
||||
Allocator &_alloc;
|
||||
|
||||
Id const _id;
|
||||
|
||||
struct Hosted_key : List_model<Hosted_key>::Element, Hosted<Hbox, Key>
|
||||
{
|
||||
using Hosted::Hosted;
|
||||
};
|
||||
|
||||
List_model<Hosted_key> keys { };
|
||||
|
||||
Row(Allocator &alloc, Id const id) : _alloc(alloc), _id(id) { }
|
||||
|
||||
bool matches(Xml_node const &node) const { return _id == _id_attr(node); }
|
||||
|
||||
static bool type_matches(Xml_node const &node) { return node.type() == "row"; }
|
||||
|
||||
void update(Xml_node const &row)
|
||||
{
|
||||
keys.update_from_xml(row,
|
||||
|
||||
/* create */
|
||||
[&] (Xml_node const &node) -> Hosted_key & {
|
||||
Id const id = _id_attr(node);
|
||||
return *new (_alloc) Hosted_key { id, id }; },
|
||||
|
||||
/* destroy */
|
||||
[&] (Hosted_key &key) { destroy(_alloc, &key); },
|
||||
|
||||
/* update */
|
||||
[&] (Hosted_key &key, Xml_node const &node) { key.update(node); });
|
||||
}
|
||||
|
||||
struct Attr { Default_key_min_ex default_key_min_ex; };
|
||||
|
||||
void view(Scope<Hbox> &, Attr const &) const;
|
||||
|
||||
void click(Clicked_at const &at, auto const &fn)
|
||||
{
|
||||
keys.for_each([&] (Hosted_key &key) {
|
||||
key.propagate(at, fn); });
|
||||
}
|
||||
};
|
||||
|
||||
struct Map : List_model<Map>::Element
|
||||
{
|
||||
Allocator &_alloc;
|
||||
|
||||
using Name = String<16>;
|
||||
Name const name;
|
||||
|
||||
static Name name_attr(Xml_node const &node) {
|
||||
return node.attribute_value("name", Name()); }
|
||||
|
||||
struct Hosted_row : List_model<Hosted_row>::Element, Hosted<Vbox, Row>
|
||||
{
|
||||
using Hosted::Hosted;
|
||||
};
|
||||
|
||||
List_model<Hosted_row> rows { };
|
||||
|
||||
Map(Allocator &alloc, Name name) : _alloc(alloc), name(name) { }
|
||||
|
||||
bool matches(Xml_node const &node) const { return name == name_attr(node); }
|
||||
|
||||
static bool type_matches(Xml_node const &node) { return node.type() == "map"; }
|
||||
|
||||
void update(Xml_node const &map)
|
||||
{
|
||||
rows.update_from_xml(map,
|
||||
|
||||
/* create */
|
||||
[&] (Xml_node const &node) -> Hosted_row & {
|
||||
Id const id = _id_attr(node);
|
||||
return *new (_alloc) Hosted_row { id, _alloc, id }; },
|
||||
|
||||
/* destroy */
|
||||
[&] (Hosted_row &row) { destroy(_alloc, &row); },
|
||||
|
||||
/* update */
|
||||
[&] (Hosted_row &row, Xml_node const &node) { row.update(node); });
|
||||
}
|
||||
};
|
||||
|
||||
List_model<Map> _maps { };
|
||||
|
||||
Map::Name _current_map = "lower";
|
||||
|
||||
Emit _emit_on_clack { };
|
||||
|
||||
static void _with_current_map(auto &keyboard, auto const &fn)
|
||||
{
|
||||
keyboard._maps.for_each([&] (auto &map) {
|
||||
if (map.name == keyboard._current_map)
|
||||
fn(map); });
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Touch_keyboard_widget(Allocator &alloc) : _alloc(alloc) { }
|
||||
|
||||
void configure(Xml_node const &config)
|
||||
{
|
||||
_default_key_min_ex = { config.attribute_value("key_min_ex", 0U) };
|
||||
|
||||
_maps.update_from_xml(config,
|
||||
|
||||
/* create */
|
||||
[&] (Xml_node const &node) -> Map & {
|
||||
return *new (_alloc) Map(_alloc, Map::name_attr(node)); },
|
||||
|
||||
/* destroy */
|
||||
[&] (Map &map) { destroy(_alloc, &map); },
|
||||
|
||||
/* update */
|
||||
[&] (Map &map, Xml_node const &node) { map.update(node); });
|
||||
}
|
||||
|
||||
void view(Scope<Vbox> &s) const;
|
||||
|
||||
void click(Clicked_at const &);
|
||||
|
||||
void clack(Clacked_at const &, auto const &fn)
|
||||
{
|
||||
if (_emit_on_clack.length() > 1) {
|
||||
fn(_emit_on_clack);
|
||||
_emit_on_clack = { };
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _TOUCH_KEYBOARD_DIALOG_H_ */
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* \brief Common types
|
||||
* \author Norman Feske
|
||||
* \date 2020-01-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
namespace Genode { }
|
||||
|
||||
namespace Touch_keyboard { using namespace Genode; }
|
||||
|
||||
#endif /* _TYPES_H_ */
|
Loading…
Reference in New Issue
Block a user