2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Nitpicker main program for Genode
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2006-08-04
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2006-2017 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/sleep.h>
|
2016-07-13 16:30:38 +02:00
|
|
|
#include <base/log.h>
|
|
|
|
#include <base/component.h>
|
2013-10-14 21:31:14 +02:00
|
|
|
#include <base/allocator_guard.h>
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
#include <base/heap.h>
|
2016-07-13 16:30:38 +02:00
|
|
|
#include <base/attached_ram_dataspace.h>
|
|
|
|
#include <base/attached_rom_dataspace.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <input/event.h>
|
|
|
|
#include <input/keycodes.h>
|
|
|
|
#include <root/component.h>
|
|
|
|
#include <dataspace/client.h>
|
|
|
|
#include <timer_session/connection.h>
|
|
|
|
#include <input_session/connection.h>
|
|
|
|
#include <input_session/input_session.h>
|
|
|
|
#include <nitpicker_session/nitpicker_session.h>
|
|
|
|
#include <framebuffer_session/connection.h>
|
2013-12-28 20:35:56 +01:00
|
|
|
#include <util/color.h>
|
2013-12-28 22:29:30 +01:00
|
|
|
#include <os/pixel_rgb565.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <os/session_policy.h>
|
2014-01-11 02:14:09 +01:00
|
|
|
#include <os/reporter.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* local includes */
|
2013-09-07 23:48:40 +02:00
|
|
|
#include "input.h"
|
2011-12-22 16:19:25 +01:00
|
|
|
#include "background.h"
|
|
|
|
#include "clip_guard.h"
|
2014-07-02 22:00:15 +02:00
|
|
|
#include "pointer_origin.h"
|
2014-06-13 11:37:34 +02:00
|
|
|
#include "domain_registry.h"
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
namespace Input { class Session_component; }
|
|
|
|
namespace Framebuffer { class Session_component; }
|
2014-06-06 17:26:53 +02:00
|
|
|
|
2013-09-08 16:20:18 +02:00
|
|
|
namespace Nitpicker {
|
|
|
|
class Session_component;
|
|
|
|
template <typename> class Root;
|
|
|
|
struct Main;
|
|
|
|
}
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
using Genode::size_t;
|
|
|
|
using Genode::Allocator;
|
2016-07-13 16:30:38 +02:00
|
|
|
using Genode::Entrypoint;
|
2013-12-28 22:29:30 +01:00
|
|
|
using Genode::List;
|
|
|
|
using Genode::Pixel_rgb565;
|
|
|
|
using Genode::strcmp;
|
2016-07-13 16:30:38 +02:00
|
|
|
using Genode::Env;
|
2013-12-28 22:29:30 +01:00
|
|
|
using Genode::Arg_string;
|
|
|
|
using Genode::Object_pool;
|
|
|
|
using Genode::Dataspace_capability;
|
|
|
|
using Genode::Session_label;
|
|
|
|
using Genode::Signal_transmitter;
|
|
|
|
using Genode::Signal_context_capability;
|
2016-07-13 16:30:38 +02:00
|
|
|
using Genode::Signal_handler;
|
2013-12-28 22:29:30 +01:00
|
|
|
using Genode::Attached_ram_dataspace;
|
2016-07-13 16:30:38 +02:00
|
|
|
using Genode::Attached_rom_dataspace;
|
2014-02-11 15:11:31 +01:00
|
|
|
using Genode::Attached_dataspace;
|
2014-06-06 17:26:53 +02:00
|
|
|
using Genode::Weak_ptr;
|
|
|
|
using Genode::Locked_ptr;
|
2013-12-28 22:29:30 +01:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-04-30 13:51:45 +02:00
|
|
|
Framebuffer::Session *tmp_fb;
|
|
|
|
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/***************
|
|
|
|
** Utilities **
|
|
|
|
***************/
|
|
|
|
|
2015-09-24 14:48:08 +02:00
|
|
|
static void report_session(Genode::Reporter &reporter, Session *session,
|
|
|
|
bool active = false)
|
2014-07-08 17:35:40 +02:00
|
|
|
{
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!reporter.enabled())
|
2014-07-08 17:35:40 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
Genode::Reporter::Xml_generator xml(reporter, [&] ()
|
|
|
|
{
|
2014-12-04 15:30:38 +01:00
|
|
|
if (session) {
|
|
|
|
xml.attribute("label", session->label().string());
|
|
|
|
xml.attribute("domain", session->domain_name().string());
|
2014-07-08 17:35:40 +02:00
|
|
|
|
2014-12-04 15:30:38 +01:00
|
|
|
Color const color = session->color();
|
2014-07-08 17:35:40 +02:00
|
|
|
char buf[32];
|
|
|
|
Genode::snprintf(buf, sizeof(buf), "#%02x%02x%02x",
|
|
|
|
color.r, color.g, color.b);
|
|
|
|
xml.attribute("color", buf);
|
2015-09-24 14:48:08 +02:00
|
|
|
|
|
|
|
if (active) xml.attribute("active", "yes");
|
2014-07-08 17:35:40 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* Font initialization
|
|
|
|
*/
|
|
|
|
extern char _binary_default_tff_start;
|
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
Text_painter::Font default_font(&_binary_default_tff_start);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
template <typename PT>
|
2014-04-30 13:51:45 +02:00
|
|
|
struct Screen : public Canvas<PT>
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2014-04-30 13:51:45 +02:00
|
|
|
Screen(PT *base, Area size) : Canvas<PT>(base, size) { }
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Buffer
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
Area _size;
|
2012-01-18 14:57:08 +01:00
|
|
|
Framebuffer::Mode::Format _format;
|
2011-12-22 16:19:25 +01:00
|
|
|
Genode::Attached_ram_dataspace _ram_ds;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor - allocate and map dataspace for virtual frame buffer
|
|
|
|
*
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
* \throw Out_of_ram
|
|
|
|
* \throw Out_of_caps
|
|
|
|
* \throw Region_map::Region_conflict
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
Buffer(Genode::Ram_session &ram, Genode::Region_map &rm,
|
|
|
|
Area size, Framebuffer::Mode::Format format, Genode::size_t bytes)
|
2013-09-09 22:39:54 +02:00
|
|
|
:
|
2016-07-13 16:30:38 +02:00
|
|
|
_size(size), _format(format), _ram_ds(ram, rm, bytes)
|
2011-12-22 16:19:25 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Accessors
|
|
|
|
*/
|
2013-09-09 22:39:54 +02:00
|
|
|
Genode::Ram_dataspace_capability ds_cap() const { return _ram_ds.cap(); }
|
2013-12-28 22:29:30 +01:00
|
|
|
Area size() const { return _size; }
|
2013-09-09 22:39:54 +02:00
|
|
|
Framebuffer::Mode::Format format() const { return _format; }
|
|
|
|
void *local_addr() const { return _ram_ds.local_addr<void>(); }
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
/**
|
|
|
|
* Interface for triggering the re-allocation of a virtual framebuffer
|
|
|
|
*
|
|
|
|
* Used by 'Framebuffer::Session_component',
|
|
|
|
* implemented by 'Nitpicker::Session_component'
|
|
|
|
*/
|
|
|
|
struct Buffer_provider
|
|
|
|
{
|
|
|
|
virtual Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
template <typename PT>
|
2013-12-28 22:29:30 +01:00
|
|
|
class Chunky_dataspace_texture : public Buffer,
|
|
|
|
public Texture<PT>
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2012-01-18 14:57:08 +01:00
|
|
|
Framebuffer::Mode::Format _format() {
|
|
|
|
return Framebuffer::Mode::RGB565; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return base address of alpha channel or 0 if no alpha channel exists
|
|
|
|
*/
|
2013-12-28 22:29:30 +01:00
|
|
|
unsigned char *_alpha_base(Area size, bool use_alpha)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
if (!use_alpha) return 0;
|
|
|
|
|
|
|
|
/* alpha values come right after the pixel values */
|
|
|
|
return (unsigned char *)local_addr() + calc_num_bytes(size, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
Chunky_dataspace_texture(Genode::Ram_session &ram, Genode::Region_map &rm,
|
|
|
|
Area size, bool use_alpha)
|
2013-09-09 22:39:54 +02:00
|
|
|
:
|
2016-07-13 16:30:38 +02:00
|
|
|
Buffer(ram, rm, size, _format(), calc_num_bytes(size, use_alpha)),
|
2013-12-28 22:29:30 +01:00
|
|
|
Texture<PT>((PT *)local_addr(),
|
|
|
|
_alpha_base(size, use_alpha), size) { }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
static Genode::size_t calc_num_bytes(Area size, bool use_alpha)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If using an alpha channel, the alpha buffer follows the
|
|
|
|
* pixel buffer. The alpha buffer is followed by an input
|
|
|
|
* mask buffer. Hence, we have to account one byte per
|
|
|
|
* alpha value and one byte for the input mask value.
|
|
|
|
*/
|
|
|
|
Genode::size_t bytes_per_pixel = sizeof(PT) + (use_alpha ? 2 : 0);
|
|
|
|
return bytes_per_pixel*size.w()*size.h();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char *input_mask_buffer()
|
|
|
|
{
|
2013-12-28 22:29:30 +01:00
|
|
|
if (!Texture<PT>::alpha()) return 0;
|
|
|
|
|
|
|
|
Area const size = Texture<PT>::size();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* input-mask values come right after the alpha values */
|
2013-12-28 22:29:30 +01:00
|
|
|
return (unsigned char *)local_addr() + calc_num_bytes(size, false)
|
|
|
|
+ size.count();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/***********************
|
|
|
|
** Input sub session **
|
|
|
|
***********************/
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
class Input::Session_component : public Genode::Rpc_object<Session>
|
|
|
|
{
|
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
enum { MAX_EVENTS = 200 };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-09 22:39:54 +02:00
|
|
|
static size_t ev_ds_size() {
|
2013-12-28 22:29:30 +01:00
|
|
|
return Genode::align_addr(MAX_EVENTS*sizeof(Event), 12); }
|
2013-09-09 22:39:54 +02:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/*
|
|
|
|
* Exported event buffer dataspace
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
Attached_ram_dataspace _ev_ram_ds;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/*
|
|
|
|
* Local event buffer that is copied
|
|
|
|
* to the exported event buffer when
|
|
|
|
* flush() gets called.
|
|
|
|
*/
|
|
|
|
Event _ev_buf[MAX_EVENTS];
|
2013-09-09 22:39:54 +02:00
|
|
|
unsigned _num_ev = 0;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-05-07 10:33:20 +02:00
|
|
|
Signal_context_capability _sigh;
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Session_component(Genode::Env &env)
|
|
|
|
:
|
|
|
|
_ev_ram_ds(env.ram(), env.rm(), ev_ds_size())
|
|
|
|
{ }
|
|
|
|
|
2014-05-07 10:33:20 +02:00
|
|
|
/**
|
|
|
|
* Wake up client
|
|
|
|
*/
|
|
|
|
void submit_signal()
|
|
|
|
{
|
|
|
|
if (_sigh.valid())
|
|
|
|
Signal_transmitter(_sigh).submit();
|
|
|
|
}
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/**
|
|
|
|
* Enqueue event into local event buffer of the input session
|
|
|
|
*/
|
|
|
|
void submit(const Event *ev)
|
|
|
|
{
|
|
|
|
/* drop event when event buffer is full */
|
|
|
|
if (_num_ev >= MAX_EVENTS) return;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/* insert event into local event buffer */
|
|
|
|
_ev_buf[_num_ev++] = *ev;
|
2014-05-07 10:33:20 +02:00
|
|
|
|
|
|
|
submit_signal();
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/*****************************
|
|
|
|
** Input session interface **
|
|
|
|
*****************************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-05-07 10:33:20 +02:00
|
|
|
Dataspace_capability dataspace() override { return _ev_ram_ds.cap(); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
bool pending() const override { return _num_ev > 0; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-05-07 10:33:20 +02:00
|
|
|
int flush() override
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
|
|
|
unsigned ev_cnt;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/* copy events from local event buffer to exported buffer */
|
|
|
|
Event *ev_ds_buf = _ev_ram_ds.local_addr<Event>();
|
|
|
|
for (ev_cnt = 0; ev_cnt < _num_ev; ev_cnt++)
|
|
|
|
ev_ds_buf[ev_cnt] = _ev_buf[ev_cnt];
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
_num_ev = 0;
|
|
|
|
return ev_cnt;
|
|
|
|
}
|
2014-05-07 10:33:20 +02:00
|
|
|
|
|
|
|
void sigh(Genode::Signal_context_capability sigh) override { _sigh = sigh; }
|
2013-09-07 23:48:40 +02:00
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************
|
|
|
|
** Framebuffer sub session **
|
|
|
|
*****************************/
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
|
|
|
{
|
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
::Buffer *_buffer = 0;
|
|
|
|
View_stack &_view_stack;
|
|
|
|
::Session &_session;
|
|
|
|
Framebuffer::Session &_framebuffer;
|
|
|
|
Buffer_provider &_buffer_provider;
|
|
|
|
Signal_context_capability _mode_sigh;
|
2014-04-29 15:32:09 +02:00
|
|
|
Signal_context_capability _sync_sigh;
|
2013-10-14 21:31:14 +02:00
|
|
|
Framebuffer::Mode _mode;
|
|
|
|
bool _alpha = false;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2013-10-14 21:31:14 +02:00
|
|
|
Session_component(View_stack &view_stack,
|
|
|
|
::Session &session,
|
|
|
|
Framebuffer::Session &framebuffer,
|
|
|
|
Buffer_provider &buffer_provider)
|
2013-09-07 23:48:40 +02:00
|
|
|
:
|
2013-10-14 21:31:14 +02:00
|
|
|
_view_stack(view_stack),
|
|
|
|
_session(session),
|
|
|
|
_framebuffer(framebuffer),
|
|
|
|
_buffer_provider(buffer_provider)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change virtual framebuffer mode
|
|
|
|
*
|
|
|
|
* Called by Nitpicker::Session_component when re-dimensioning the
|
|
|
|
* buffer.
|
|
|
|
*
|
|
|
|
* The new mode does not immediately become active. The client can
|
|
|
|
* keep using an already obtained framebuffer dataspace. However,
|
|
|
|
* we inform the client about the mode change via a signal. If the
|
|
|
|
* client calls 'dataspace' the next time, the new mode becomes
|
|
|
|
* effective.
|
|
|
|
*/
|
|
|
|
void notify_mode_change(Framebuffer::Mode mode, bool alpha)
|
|
|
|
{
|
|
|
|
_mode = mode;
|
|
|
|
_alpha = alpha;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
if (_mode_sigh.valid())
|
|
|
|
Signal_transmitter(_mode_sigh).submit();
|
|
|
|
}
|
|
|
|
|
2014-04-30 13:51:45 +02:00
|
|
|
void submit_sync()
|
|
|
|
{
|
|
|
|
if (_sync_sigh.valid())
|
|
|
|
Signal_transmitter(_sync_sigh).submit();
|
|
|
|
}
|
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
|
|
|
|
/************************************
|
|
|
|
** Framebuffer::Session interface **
|
|
|
|
************************************/
|
|
|
|
|
2014-04-29 15:32:09 +02:00
|
|
|
Dataspace_capability dataspace() override
|
2013-10-14 21:31:14 +02:00
|
|
|
{
|
|
|
|
_buffer = _buffer_provider.realloc_buffer(_mode, _alpha);
|
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
return _buffer ? _buffer->ds_cap() : Genode::Ram_dataspace_capability();
|
2013-10-14 21:31:14 +02:00
|
|
|
}
|
2012-01-20 21:34:01 +01:00
|
|
|
|
2014-04-29 15:32:09 +02:00
|
|
|
Mode mode() const override { return _mode; }
|
|
|
|
|
|
|
|
void mode_sigh(Signal_context_capability sigh) override
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
2014-04-29 15:32:09 +02:00
|
|
|
_mode_sigh = sigh;
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
2012-01-20 21:34:01 +01:00
|
|
|
|
2014-04-29 15:32:09 +02:00
|
|
|
void sync_sigh(Signal_context_capability sigh) override
|
2013-10-14 21:31:14 +02:00
|
|
|
{
|
2014-04-29 15:32:09 +02:00
|
|
|
_sync_sigh = sigh;
|
2013-10-14 21:31:14 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-04-29 15:32:09 +02:00
|
|
|
void refresh(int x, int y, int w, int h) override
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
2014-04-30 13:51:45 +02:00
|
|
|
Rect const rect(Point(x, y), Area(w, h));
|
2014-04-29 15:32:09 +02:00
|
|
|
|
2014-04-30 13:51:45 +02:00
|
|
|
_view_stack.mark_session_views_as_dirty(_session, rect);
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
** Implementation of Nitpicker service **
|
|
|
|
*****************************************/
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
|
2013-10-14 21:31:14 +02:00
|
|
|
public ::Session,
|
|
|
|
public Buffer_provider
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
typedef ::View View;
|
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Env &_env;
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
Genode::Allocator_guard _session_alloc;
|
2013-10-14 21:31:14 +02:00
|
|
|
|
|
|
|
Framebuffer::Session &_framebuffer;
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/* Framebuffer_session_component */
|
|
|
|
Framebuffer::Session_component _framebuffer_session_component;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/* Input_session_component */
|
2016-07-13 16:30:38 +02:00
|
|
|
Input::Session_component _input_session_component { _env };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
View_stack &_view_stack;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-04 15:58:49 +02:00
|
|
|
Mode &_mode;
|
|
|
|
|
2014-07-09 10:34:02 +02:00
|
|
|
Signal_context_capability _mode_sigh;
|
|
|
|
|
2014-07-02 17:37:02 +02:00
|
|
|
View &_pointer_origin;
|
|
|
|
|
2017-09-22 11:09:02 +02:00
|
|
|
View &_builtin_background;
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
List<Session_view_list_elem> _view_list;
|
|
|
|
|
|
|
|
Genode::Tslab<View, 4000> _view_alloc { &_session_alloc };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/* capabilities for sub sessions */
|
|
|
|
Framebuffer::Session_capability _framebuffer_session_cap;
|
|
|
|
Input::Session_capability _input_session_cap;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-09 22:39:54 +02:00
|
|
|
bool const _provides_default_bg;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
/* size of currently allocated virtual framebuffer, in bytes */
|
|
|
|
size_t _buffer_size = 0;
|
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Attached_ram_dataspace _command_ds { _env.ram(), _env.rm(),
|
2014-06-06 17:26:53 +02:00
|
|
|
sizeof(Command_buffer) };
|
|
|
|
|
|
|
|
Command_buffer &_command_buffer = *_command_ds.local_addr<Command_buffer>();
|
|
|
|
|
|
|
|
typedef Genode::Handle_registry<View_handle, View> View_handle_registry;
|
|
|
|
|
|
|
|
View_handle_registry _view_handle_registry;
|
|
|
|
|
2014-07-08 17:35:40 +02:00
|
|
|
Genode::Reporter &_focus_reporter;
|
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
void _release_buffer()
|
|
|
|
{
|
|
|
|
if (!::Session::texture())
|
|
|
|
return;
|
|
|
|
|
|
|
|
typedef Pixel_rgb565 PT;
|
|
|
|
|
|
|
|
/* retrieve pointer to texture from session */
|
|
|
|
Chunky_dataspace_texture<PT> const *cdt =
|
|
|
|
static_cast<Chunky_dataspace_texture<PT> const *>(::Session::texture());
|
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
::Session::texture(0, false);
|
2013-10-14 21:31:14 +02:00
|
|
|
::Session::input_mask(0);
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
destroy(&_session_alloc, const_cast<Chunky_dataspace_texture<PT> *>(cdt));
|
2013-10-14 21:31:14 +02:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
_session_alloc.upgrade(_buffer_size);
|
2013-10-14 21:31:14 +02:00
|
|
|
_buffer_size = 0;
|
|
|
|
}
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
/**
|
|
|
|
* Helper for performing sanity checks in OP_TO_FRONT and OP_TO_BACK
|
|
|
|
*
|
|
|
|
* We have to check for the equality of both the specified view and
|
|
|
|
* neighbor. If both arguments refer to the same view, the creation of
|
|
|
|
* locked pointers for both views would result in a deadlock.
|
|
|
|
*/
|
|
|
|
bool _views_are_equal(View_handle v1, View_handle v2)
|
|
|
|
{
|
|
|
|
if (!v1.valid() || !v2.valid())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Weak_ptr<View> v1_ptr = _view_handle_registry.lookup(v1);
|
|
|
|
Weak_ptr<View> v2_ptr = _view_handle_registry.lookup(v2);
|
|
|
|
|
|
|
|
return v1_ptr == v2_ptr;
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:58:49 +02:00
|
|
|
bool _focus_change_permitted() const
|
|
|
|
{
|
|
|
|
::Session * const focused_session = _mode.focused_session();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If no session is focused, we allow any client to assign it. This
|
|
|
|
* is useful for programs such as an initial login window that
|
|
|
|
* should receive input events without prior manual selection via
|
|
|
|
* the mouse.
|
|
|
|
*
|
|
|
|
* In principle, a client could steal the focus during time between
|
|
|
|
* a currently focused session gets closed and before the user
|
|
|
|
* manually picks a new session. However, in practice, the focus
|
|
|
|
* policy during application startup and exit is managed by a
|
|
|
|
* window manager that sits between nitpicker and the application.
|
|
|
|
*/
|
|
|
|
if (!focused_session)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the currently focused session label belongs to a
|
|
|
|
* session subordinated to the caller, i.e., it originated from
|
|
|
|
* a child of the caller or from the same process. This is the
|
|
|
|
* case if the first part of the focused session label is
|
|
|
|
* identical to the caller's label.
|
|
|
|
*/
|
|
|
|
char const * const focused_label = focused_session->label().string();
|
|
|
|
char const * const caller_label = label().string();
|
|
|
|
|
|
|
|
return strcmp(focused_label, caller_label, Genode::strlen(caller_label)) == 0;
|
|
|
|
}
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
void _execute_command(Command const &command)
|
|
|
|
{
|
|
|
|
switch (command.opcode) {
|
|
|
|
|
|
|
|
case Command::OP_GEOMETRY:
|
|
|
|
{
|
2017-03-27 12:35:23 +02:00
|
|
|
Command::Geometry const &cmd = command.geometry;
|
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(cmd.view));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!view.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
|
2017-03-27 12:35:23 +02:00
|
|
|
Point pos = cmd.rect.p1();
|
2014-06-06 17:26:53 +02:00
|
|
|
|
2014-07-08 16:19:21 +02:00
|
|
|
/* transpose position of top-level views by vertical session offset */
|
2014-06-06 17:26:53 +02:00
|
|
|
if (view->top_level())
|
2014-07-08 16:19:21 +02:00
|
|
|
pos = ::Session::phys_pos(pos, _view_stack.size());
|
2014-06-06 17:26:53 +02:00
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (view.valid())
|
2017-03-27 12:35:23 +02:00
|
|
|
_view_stack.geometry(*view, Rect(pos, cmd.rect.area()));
|
2014-06-06 17:26:53 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Command::OP_OFFSET:
|
|
|
|
{
|
2017-03-27 12:35:23 +02:00
|
|
|
Command::Offset const &cmd = command.offset;
|
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(cmd.view));
|
2014-06-06 17:26:53 +02:00
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (view.valid())
|
2017-03-27 12:35:23 +02:00
|
|
|
_view_stack.buffer_offset(*view, cmd.offset);
|
2014-06-06 17:26:53 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Command::OP_TO_FRONT:
|
|
|
|
{
|
2017-03-27 12:35:23 +02:00
|
|
|
Command::To_front const &cmd = command.to_front;
|
|
|
|
if (_views_are_equal(cmd.view, cmd.neighbor))
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
|
2017-03-27 12:35:23 +02:00
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(cmd.view));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!view.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* bring to front if no neighbor is specified */
|
2017-03-27 12:35:23 +02:00
|
|
|
if (!cmd.neighbor.valid()) {
|
2014-06-06 17:26:53 +02:00
|
|
|
_view_stack.stack(*view, nullptr, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stack view relative to neighbor */
|
2017-03-27 12:35:23 +02:00
|
|
|
Locked_ptr<View> neighbor(_view_handle_registry.lookup(cmd.neighbor));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (neighbor.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
_view_stack.stack(*view, &(*neighbor), false);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Command::OP_TO_BACK:
|
|
|
|
{
|
2017-03-27 12:35:23 +02:00
|
|
|
Command::To_back const &cmd = command.to_back;
|
|
|
|
if (_views_are_equal(cmd.view, cmd.neighbor))
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
|
2017-03-27 12:35:23 +02:00
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(cmd.view));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!view.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* bring to front if no neighbor is specified */
|
2017-03-27 12:35:23 +02:00
|
|
|
if (!cmd.neighbor.valid()) {
|
2014-06-06 17:26:53 +02:00
|
|
|
_view_stack.stack(*view, nullptr, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stack view relative to neighbor */
|
2017-03-27 12:35:23 +02:00
|
|
|
Locked_ptr<View> neighbor(_view_handle_registry.lookup(cmd.neighbor));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (neighbor.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
_view_stack.stack(*view, &(*neighbor), true);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Command::OP_BACKGROUND:
|
|
|
|
{
|
2017-03-27 12:35:23 +02:00
|
|
|
Command::Background const &cmd = command.background;
|
2014-06-06 17:26:53 +02:00
|
|
|
if (_provides_default_bg) {
|
2017-03-27 12:35:23 +02:00
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(cmd.view));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!view.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
view->background(true);
|
|
|
|
_view_stack.default_background(*view);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* revert old background view to normal mode */
|
|
|
|
if (::Session::background())
|
|
|
|
::Session::background()->background(false);
|
|
|
|
|
|
|
|
/* assign session background */
|
2017-03-27 12:35:23 +02:00
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(cmd.view));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!view.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
::Session::background(&(*view));
|
|
|
|
|
|
|
|
/* switch background view to background mode */
|
|
|
|
if (::Session::background())
|
|
|
|
view->background(true);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Command::OP_TITLE:
|
|
|
|
{
|
2017-03-27 12:35:23 +02:00
|
|
|
Command::Title const &cmd = command.title;
|
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(cmd.view));
|
2014-06-06 17:26:53 +02:00
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (view.valid())
|
2017-03-27 12:35:23 +02:00
|
|
|
_view_stack.title(*view, cmd.title.string());
|
2014-06-06 17:26:53 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Command::OP_NOP:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _destroy_view(View &view)
|
|
|
|
{
|
2017-09-22 11:09:02 +02:00
|
|
|
/* reset background if view was used as default background */
|
|
|
|
if (_view_stack.is_default_background(view))
|
|
|
|
_view_stack.default_background(_builtin_background);
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
_view_stack.remove_view(view);
|
2016-07-13 16:30:38 +02:00
|
|
|
_env.ep().dissolve(view);
|
2014-06-06 17:26:53 +02:00
|
|
|
_view_list.remove(&view);
|
|
|
|
destroy(_view_alloc, &view);
|
|
|
|
}
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
Session_component(Env &env,
|
|
|
|
Session_label const &label,
|
2013-10-14 21:31:14 +02:00
|
|
|
View_stack &view_stack,
|
2014-06-04 15:58:49 +02:00
|
|
|
Mode &mode,
|
2014-07-02 17:37:02 +02:00
|
|
|
View &pointer_origin,
|
2017-09-22 11:09:02 +02:00
|
|
|
View &builtin_background,
|
2013-10-14 21:31:14 +02:00
|
|
|
Framebuffer::Session &framebuffer,
|
|
|
|
bool provides_default_bg,
|
2014-06-06 17:26:53 +02:00
|
|
|
Allocator &session_alloc,
|
2014-07-08 17:35:40 +02:00
|
|
|
size_t ram_quota,
|
|
|
|
Genode::Reporter &focus_reporter)
|
2013-09-07 23:48:40 +02:00
|
|
|
:
|
2014-07-08 16:19:21 +02:00
|
|
|
::Session(label),
|
2016-07-13 16:30:38 +02:00
|
|
|
_env(env),
|
2014-06-06 17:26:53 +02:00
|
|
|
_session_alloc(&session_alloc, ram_quota),
|
2013-10-14 21:31:14 +02:00
|
|
|
_framebuffer(framebuffer),
|
2014-04-30 13:51:45 +02:00
|
|
|
_framebuffer_session_component(view_stack, *this, framebuffer, *this),
|
2016-07-13 16:30:38 +02:00
|
|
|
_view_stack(view_stack), _mode(mode),
|
2014-07-02 17:37:02 +02:00
|
|
|
_pointer_origin(pointer_origin),
|
2017-09-22 11:09:02 +02:00
|
|
|
_builtin_background(builtin_background),
|
2016-07-13 16:30:38 +02:00
|
|
|
_framebuffer_session_cap(_env.ep().manage(_framebuffer_session_component)),
|
|
|
|
_input_session_cap(_env.ep().manage(_input_session_component)),
|
2014-06-06 17:26:53 +02:00
|
|
|
_provides_default_bg(provides_default_bg),
|
2014-07-08 17:35:40 +02:00
|
|
|
_view_handle_registry(_session_alloc),
|
|
|
|
_focus_reporter(focus_reporter)
|
2013-10-14 21:31:14 +02:00
|
|
|
{
|
2014-06-06 17:26:53 +02:00
|
|
|
_session_alloc.upgrade(ram_quota);
|
2013-10-14 21:31:14 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/**
|
|
|
|
* Destructor
|
|
|
|
*/
|
|
|
|
~Session_component()
|
|
|
|
{
|
2016-07-13 16:30:38 +02:00
|
|
|
_env.ep().dissolve(_framebuffer_session_component);
|
|
|
|
_env.ep().dissolve(_input_session_component);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
destroy_all_views();
|
2013-10-14 21:31:14 +02:00
|
|
|
|
|
|
|
_release_buffer();
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
void destroy_all_views()
|
|
|
|
{
|
|
|
|
while (Session_view_list_elem *v = _view_list.first())
|
|
|
|
_destroy_view(*static_cast<View *>(v));
|
|
|
|
}
|
|
|
|
|
2014-07-09 10:34:02 +02:00
|
|
|
/**
|
|
|
|
* Deliver mode-change signal to client
|
|
|
|
*/
|
|
|
|
void notify_mode_change()
|
|
|
|
{
|
|
|
|
if (_mode_sigh.valid())
|
|
|
|
Signal_transmitter(_mode_sigh).submit();
|
|
|
|
}
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
void upgrade_ram_quota(size_t ram_quota) { _session_alloc.upgrade(ram_quota); }
|
2013-10-14 21:31:14 +02:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-04-30 13:51:45 +02:00
|
|
|
/**********************************
|
|
|
|
** Nitpicker-internal interface **
|
|
|
|
**********************************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
void submit_input_event(Input::Event e)
|
|
|
|
{
|
|
|
|
using namespace Input;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-07-08 16:19:21 +02:00
|
|
|
Point const origin_offset =
|
|
|
|
::Session::phys_pos(Point(0, 0), _view_stack.size());
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/*
|
|
|
|
* Transpose absolute coordinates by session-specific vertical
|
|
|
|
* offset.
|
|
|
|
*/
|
|
|
|
if (e.ax() || e.ay())
|
2014-07-08 16:19:21 +02:00
|
|
|
e = Event(e.type(), e.code(),
|
|
|
|
Genode::max(0, e.ax() - origin_offset.x()),
|
|
|
|
Genode::max(0, e.ay() - origin_offset.y()),
|
|
|
|
e.rx(), e.ry());
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
_input_session_component.submit(&e);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-04-30 13:51:45 +02:00
|
|
|
void submit_sync() override
|
|
|
|
{
|
|
|
|
_framebuffer_session_component.submit_sync();
|
|
|
|
}
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
/*********************************
|
|
|
|
** Nitpicker session interface **
|
|
|
|
*********************************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-04 15:58:49 +02:00
|
|
|
Framebuffer::Session_capability framebuffer_session() override {
|
2013-09-07 23:48:40 +02:00
|
|
|
return _framebuffer_session_cap; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-04 15:58:49 +02:00
|
|
|
Input::Session_capability input_session() override {
|
2013-09-07 23:48:40 +02:00
|
|
|
return _input_session_cap; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
View_handle create_view(View_handle parent_handle) override
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
2014-06-06 17:26:53 +02:00
|
|
|
View *view = nullptr;
|
2014-02-14 10:36:04 +01:00
|
|
|
|
|
|
|
/*
|
2014-06-06 17:26:53 +02:00
|
|
|
* Create child view
|
2013-09-07 23:48:40 +02:00
|
|
|
*/
|
2014-06-06 17:26:53 +02:00
|
|
|
if (parent_handle.valid()) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
Locked_ptr<View> parent(_view_handle_registry.lookup(parent_handle));
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!parent.valid())
|
2014-06-06 17:26:53 +02:00
|
|
|
return View_handle();
|
|
|
|
|
|
|
|
view = new (_view_alloc)
|
|
|
|
View(*this,
|
|
|
|
View::NOT_TRANSPARENT, View::NOT_BACKGROUND,
|
|
|
|
&(*parent));
|
|
|
|
|
|
|
|
parent->add_child(*view);
|
|
|
|
}
|
|
|
|
catch (View_handle_registry::Lookup_failed) {
|
|
|
|
return View_handle(); }
|
2015-11-21 11:17:13 +01:00
|
|
|
catch (View_handle_registry::Out_of_memory) {
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Out_of_ram(); }
|
2014-06-06 17:26:53 +02:00
|
|
|
}
|
2014-02-14 10:36:04 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
/*
|
|
|
|
* Create top-level view
|
|
|
|
*/
|
|
|
|
else {
|
|
|
|
try {
|
|
|
|
view = new (_view_alloc)
|
|
|
|
View(*this,
|
|
|
|
View::NOT_TRANSPARENT, View::NOT_BACKGROUND,
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
catch (Genode::Allocator::Out_of_memory) {
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Out_of_ram(); }
|
2014-06-06 17:26:53 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-07-02 17:37:02 +02:00
|
|
|
view->apply_origin_policy(_pointer_origin);
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
_view_list.insert(view);
|
2016-07-13 16:30:38 +02:00
|
|
|
_env.ep().manage(*view);
|
2014-06-06 17:26:53 +02:00
|
|
|
|
2015-11-21 11:17:13 +01:00
|
|
|
try { return _view_handle_registry.alloc(*view); }
|
|
|
|
catch (View_handle_registry::Out_of_memory) {
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Out_of_ram(); }
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
void destroy_view(View_handle handle) override
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
2015-08-18 15:31:55 +02:00
|
|
|
/*
|
|
|
|
* Search view object given the handle
|
|
|
|
*
|
|
|
|
* We cannot look up the view directly from the
|
|
|
|
* '_view_handle_registry' because we would obtain a weak
|
|
|
|
* pointer to the view object. If we called the object's
|
|
|
|
* destructor from the corresponding locked pointer, the
|
|
|
|
* call of 'lock_for_destruction' in the view's destructor
|
|
|
|
* would attempt to take the lock again.
|
|
|
|
*/
|
|
|
|
for (Session_view_list_elem *v = _view_list.first(); v; v = v->next()) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
View &view = *static_cast<View *>(v);
|
|
|
|
if (_view_handle_registry.has_handle(view, handle)) {
|
|
|
|
_destroy_view(view);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} catch (View_handle_registry::Lookup_failed) { }
|
2014-06-06 17:26:53 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
_view_handle_registry.free(handle);
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
View_handle view_handle(View_capability view_cap, View_handle handle) override
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
2015-08-10 13:34:16 +02:00
|
|
|
auto lambda = [&] (View *view)
|
|
|
|
{
|
|
|
|
return (view) ? _view_handle_registry.alloc(*view, handle)
|
|
|
|
: View_handle();
|
|
|
|
};
|
2015-11-21 11:17:13 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
try { return _env.ep().rpc_ep().apply(view_cap, lambda); }
|
2015-11-21 11:17:13 +01:00
|
|
|
catch (View_handle_registry::Out_of_memory) {
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Out_of_ram(); }
|
2014-06-06 17:26:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
View_capability view_capability(View_handle handle) override
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
Locked_ptr<View> view(_view_handle_registry.lookup(handle));
|
2016-05-11 18:21:47 +02:00
|
|
|
return view.valid() ? view->cap() : View_capability();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2014-06-06 17:26:53 +02:00
|
|
|
catch (View_handle_registry::Lookup_failed) {
|
|
|
|
return View_capability();
|
|
|
|
}
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
void release_view_handle(View_handle handle) override
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
_view_handle_registry.free(handle); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
catch (View_handle_registry::Lookup_failed) {
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::warning("view lookup failed while releasing view handle");
|
2014-06-06 17:26:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
Genode::Dataspace_capability command_dataspace() override
|
|
|
|
{
|
|
|
|
return _command_ds.cap();
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
void execute() override
|
|
|
|
{
|
|
|
|
for (unsigned i = 0; i < _command_buffer.num(); i++) {
|
|
|
|
try {
|
|
|
|
_execute_command(_command_buffer.get(i)); }
|
|
|
|
catch (View_handle_registry::Lookup_failed) {
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::warning("view lookup failed during command execution"); }
|
2014-06-06 17:26:53 +02:00
|
|
|
}
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
2013-10-14 21:31:14 +02:00
|
|
|
|
2014-06-04 15:58:49 +02:00
|
|
|
Framebuffer::Mode mode() override
|
2013-10-14 21:31:14 +02:00
|
|
|
{
|
2014-07-08 16:19:21 +02:00
|
|
|
Area const phys_area(_framebuffer.mode().width(),
|
|
|
|
_framebuffer.mode().height());
|
|
|
|
|
|
|
|
Area const session_area = ::Session::screen_area(phys_area);
|
2013-10-14 21:31:14 +02:00
|
|
|
|
2014-07-08 16:19:21 +02:00
|
|
|
return Framebuffer::Mode(session_area.w(), session_area.h(),
|
2013-10-14 21:31:14 +02:00
|
|
|
_framebuffer.mode().format());
|
|
|
|
}
|
|
|
|
|
2014-07-09 10:34:02 +02:00
|
|
|
void mode_sigh(Signal_context_capability sigh) override
|
|
|
|
{
|
|
|
|
_mode_sigh = sigh;
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:58:49 +02:00
|
|
|
void buffer(Framebuffer::Mode mode, bool use_alpha) override
|
2013-10-14 21:31:14 +02:00
|
|
|
{
|
|
|
|
/* check if the session quota suffices for the specified mode */
|
2014-06-06 17:26:53 +02:00
|
|
|
if (_session_alloc.quota() < ram_quota(mode, use_alpha))
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Out_of_ram();
|
2013-10-14 21:31:14 +02:00
|
|
|
|
|
|
|
_framebuffer_session_component.notify_mode_change(mode, use_alpha);
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:58:49 +02:00
|
|
|
void focus(Genode::Capability<Nitpicker::Session> session_cap) override
|
|
|
|
{
|
|
|
|
/* check permission by comparing session labels */
|
|
|
|
if (!_focus_change_permitted()) {
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::warning("unauthorized focus change requesed by ", label().string());
|
2014-06-04 15:58:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lookup targeted session object */
|
2015-08-10 13:34:16 +02:00
|
|
|
auto lambda = [this] (Session_component *session)
|
|
|
|
{
|
2015-10-08 00:09:10 +02:00
|
|
|
_mode.next_focused_session(session);
|
2015-08-10 13:34:16 +02:00
|
|
|
};
|
2016-07-13 16:30:38 +02:00
|
|
|
_env.ep().rpc_ep().apply(session_cap, lambda);
|
2015-09-15 15:02:16 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/*
|
2015-10-08 00:09:10 +02:00
|
|
|
* To avoid changing the focus in the middle of a drag operation,
|
|
|
|
* we cannot perform the focus change immediately. Instead, it
|
|
|
|
* comes into effect via the 'Mode::apply_pending_focus_change()'
|
|
|
|
* function called the next time when the user input is handled and
|
|
|
|
* no drag operation is in flight.
|
2015-09-30 11:30:02 +02:00
|
|
|
*/
|
2014-06-04 15:58:49 +02:00
|
|
|
}
|
|
|
|
|
2014-10-04 18:50:06 +02:00
|
|
|
void session_control(Label suffix, Session_control control) override
|
|
|
|
{
|
2017-01-10 17:50:34 +01:00
|
|
|
Session_label const selector(label(), suffix);
|
2014-10-04 18:50:06 +02:00
|
|
|
|
|
|
|
switch (control) {
|
2017-01-10 17:50:34 +01:00
|
|
|
case SESSION_CONTROL_HIDE: _view_stack.visible(selector.string(), false); break;
|
|
|
|
case SESSION_CONTROL_SHOW: _view_stack.visible(selector.string(), true); break;
|
|
|
|
case SESSION_CONTROL_TO_FRONT: _view_stack.to_front(selector.string()); break;
|
2014-10-04 18:50:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
|
|
|
|
/*******************************
|
|
|
|
** Buffer_provider interface **
|
|
|
|
*******************************/
|
|
|
|
|
|
|
|
Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha)
|
|
|
|
{
|
2014-07-25 14:22:03 +02:00
|
|
|
typedef Pixel_rgb565 PT;
|
2013-10-14 21:31:14 +02:00
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
Area const size(mode.width(), mode.height());
|
2013-10-14 21:31:14 +02:00
|
|
|
|
|
|
|
_buffer_size =
|
|
|
|
Chunky_dataspace_texture<PT>::calc_num_bytes(size, use_alpha);
|
|
|
|
|
2014-07-25 14:22:03 +02:00
|
|
|
/*
|
|
|
|
* Preserve the content of the original buffer if nitpicker has
|
|
|
|
* enough lack memory to temporarily keep the original pixels.
|
|
|
|
*/
|
|
|
|
Texture<PT> const *src_texture = nullptr;
|
|
|
|
if (::Session::texture()) {
|
|
|
|
|
|
|
|
enum { PRESERVED_RAM = 128*1024 };
|
2017-05-08 01:33:40 +02:00
|
|
|
if (_env.ram().avail_ram().value > _buffer_size + PRESERVED_RAM) {
|
2014-07-25 14:22:03 +02:00
|
|
|
src_texture = static_cast<Texture<PT> const *>(::Session::texture());
|
|
|
|
} else {
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::warning("not enough RAM to preserve buffer content during resize");
|
2014-07-25 14:22:03 +02:00
|
|
|
_release_buffer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Chunky_dataspace_texture<PT> * const texture = new (&_session_alloc)
|
|
|
|
Chunky_dataspace_texture<PT>(_env.ram(), _env.rm(), size, use_alpha);
|
2013-10-14 21:31:14 +02:00
|
|
|
|
2014-07-25 14:22:03 +02:00
|
|
|
/* copy old buffer content into new buffer and release old buffer */
|
|
|
|
if (src_texture) {
|
|
|
|
|
|
|
|
Genode::Surface<PT> surface(texture->pixel(),
|
|
|
|
texture->Texture_base::size());
|
|
|
|
|
|
|
|
Texture_painter::paint(surface, *src_texture, Color(), Point(0, 0),
|
|
|
|
Texture_painter::SOLID, false);
|
|
|
|
_release_buffer();
|
|
|
|
}
|
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
if (!_session_alloc.withdraw(_buffer_size)) {
|
|
|
|
destroy(&_session_alloc, texture);
|
2013-10-14 21:31:14 +02:00
|
|
|
_buffer_size = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-28 22:29:30 +01:00
|
|
|
::Session::texture(texture, use_alpha);
|
2013-10-14 21:31:14 +02:00
|
|
|
::Session::input_mask(texture->input_mask_buffer());
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
2013-09-07 23:48:40 +02:00
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
template <typename PT>
|
|
|
|
class Nitpicker::Root : public Genode::Root_component<Session_component>
|
|
|
|
{
|
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Env &_env;
|
|
|
|
Attached_rom_dataspace const &_config;
|
|
|
|
Session_list &_session_list;
|
|
|
|
Domain_registry const &_domain_registry;
|
|
|
|
Global_keys &_global_keys;
|
|
|
|
Framebuffer::Mode _scr_mode;
|
|
|
|
View_stack &_view_stack;
|
|
|
|
Mode &_mode;
|
|
|
|
::View &_pointer_origin;
|
2017-09-22 11:09:02 +02:00
|
|
|
::View &_builtin_background;
|
2016-07-13 16:30:38 +02:00
|
|
|
Framebuffer::Session &_framebuffer;
|
|
|
|
Genode::Reporter &_focus_reporter;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
protected:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
Session_component *_create_session(const char *args)
|
|
|
|
{
|
2013-09-09 22:39:54 +02:00
|
|
|
size_t const ram_quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-06-06 17:26:53 +02:00
|
|
|
size_t const required_quota = Input::Session_component::ev_ds_size()
|
|
|
|
+ Genode::align_addr(sizeof(Session::Command_buffer), 12);
|
2013-09-06 17:34:16 +02:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
if (ram_quota < required_quota) {
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::warning("Insufficient dontated ram_quota (", ram_quota,
|
|
|
|
" bytes), require ", required_quota, " bytes");
|
2017-05-08 14:32:03 +02:00
|
|
|
throw Genode::Insufficient_ram_quota();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
size_t const unused_quota = ram_quota - required_quota;
|
2013-09-06 17:34:16 +02:00
|
|
|
|
2016-01-12 14:11:58 +01:00
|
|
|
Genode::Session_label const label = Genode::label_from_args(args);
|
|
|
|
bool const provides_default_bg = (label == "backdrop");
|
2013-09-07 02:02:26 +02:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
Session_component *session = new (md_alloc())
|
2016-07-13 16:30:38 +02:00
|
|
|
Session_component(_env, label, _view_stack, _mode,
|
2017-09-22 11:09:02 +02:00
|
|
|
_pointer_origin, _builtin_background, _framebuffer,
|
2014-07-08 17:35:40 +02:00
|
|
|
provides_default_bg, *md_alloc(), unused_quota,
|
|
|
|
_focus_reporter);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
session->apply_session_policy(_config.xml(), _domain_registry);
|
2013-09-07 23:48:40 +02:00
|
|
|
_session_list.insert(session);
|
2016-07-13 16:30:38 +02:00
|
|
|
_global_keys.apply_config(_config.xml(), _session_list);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-09-07 23:48:40 +02:00
|
|
|
return session;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
void _upgrade_session(Session_component *s, const char *args)
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
2015-03-27 14:02:04 +01:00
|
|
|
size_t ram_quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0);
|
2013-10-14 21:31:14 +02:00
|
|
|
s->upgrade_ram_quota(ram_quota);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-10-14 21:31:14 +02:00
|
|
|
void _destroy_session(Session_component *session)
|
|
|
|
{
|
2013-09-07 23:48:40 +02:00
|
|
|
_session_list.remove(session);
|
2016-07-13 16:30:38 +02:00
|
|
|
_global_keys.apply_config(_config.xml(), _session_list);
|
2014-06-06 17:26:53 +02:00
|
|
|
|
|
|
|
session->destroy_all_views();
|
2014-06-04 15:58:49 +02:00
|
|
|
_mode.forget(*session);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::destroy(md_alloc(), session);
|
2013-09-07 23:48:40 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
Root(Env &env, Attached_rom_dataspace const &config,
|
|
|
|
Session_list &session_list, Domain_registry const &domain_registry,
|
|
|
|
Global_keys &global_keys, View_stack &view_stack, Mode &mode,
|
2017-09-22 11:09:02 +02:00
|
|
|
::View &pointer_origin, ::View &builtin_background, Allocator &md_alloc,
|
2014-07-08 17:35:40 +02:00
|
|
|
Framebuffer::Session &framebuffer, Genode::Reporter &focus_reporter)
|
2011-12-22 16:19:25 +01:00
|
|
|
:
|
2016-07-13 16:30:38 +02:00
|
|
|
Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc),
|
|
|
|
_env(env), _config(config),
|
2014-06-13 11:37:34 +02:00
|
|
|
_session_list(session_list), _domain_registry(domain_registry),
|
|
|
|
_global_keys(global_keys), _view_stack(view_stack), _mode(mode),
|
2017-09-22 11:09:02 +02:00
|
|
|
_pointer_origin(pointer_origin), _builtin_background(builtin_background),
|
|
|
|
_framebuffer(framebuffer),
|
2014-07-08 17:35:40 +02:00
|
|
|
_focus_reporter(focus_reporter)
|
2013-10-14 21:31:14 +02:00
|
|
|
{ }
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-09-08 16:20:18 +02:00
|
|
|
struct Nitpicker::Main
|
2013-09-06 17:34:16 +02:00
|
|
|
{
|
2016-07-13 16:30:38 +02:00
|
|
|
Env &env;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Sessions to the required external services
|
|
|
|
*/
|
2017-01-02 14:10:33 +01:00
|
|
|
Framebuffer::Connection framebuffer { env, Framebuffer::Mode() };
|
|
|
|
Input::Connection input { env };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Input::Event * const ev_buf = env.rm().attach(input.dataspace());
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2014-02-11 15:11:31 +01:00
|
|
|
typedef Pixel_rgb565 PT; /* physical pixel type */
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/*
|
2014-07-08 22:53:41 +02:00
|
|
|
* Initialize framebuffer
|
2014-02-11 15:11:31 +01:00
|
|
|
*
|
2014-07-08 22:53:41 +02:00
|
|
|
* The framebuffer is encapsulated in a volatile object to allow its
|
|
|
|
* reconstruction at runtime as a response to resolution changes.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2014-02-11 15:11:31 +01:00
|
|
|
struct Framebuffer_screen
|
|
|
|
{
|
|
|
|
Framebuffer::Session &framebuffer;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-02-11 15:11:31 +01:00
|
|
|
Framebuffer::Mode const mode = framebuffer.mode();
|
2013-09-08 16:20:18 +02:00
|
|
|
|
2017-01-02 14:10:33 +01:00
|
|
|
Attached_dataspace fb_ds;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-02-11 15:11:31 +01:00
|
|
|
Screen<PT> screen = { fb_ds.local_addr<PT>(), Area(mode.width(), mode.height()) };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-02-11 15:11:31 +01:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2017-01-02 14:10:33 +01:00
|
|
|
Framebuffer_screen(Genode::Region_map &rm, Framebuffer::Session &fb)
|
|
|
|
: framebuffer(fb), fb_ds(rm, framebuffer.dataspace()) { }
|
2014-02-11 15:11:31 +01:00
|
|
|
};
|
|
|
|
|
2017-01-02 14:10:33 +01:00
|
|
|
Genode::Reconstructible<Framebuffer_screen> fb_screen = { env.rm(), framebuffer };
|
2014-02-11 15:11:31 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
void handle_fb_mode();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Signal_handler<Main> fb_mode_handler = { env.ep(), *this, &Main::handle_fb_mode };
|
2013-09-08 16:20:18 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* User-input policy
|
|
|
|
*/
|
|
|
|
Global_keys global_keys;
|
2013-09-06 17:34:16 +02:00
|
|
|
|
2013-09-08 16:20:18 +02:00
|
|
|
Session_list session_list;
|
2013-09-06 17:34:16 +02:00
|
|
|
|
2014-06-13 11:37:34 +02:00
|
|
|
/*
|
|
|
|
* Construct empty domain registry. The initial version will be replaced
|
|
|
|
* on the first call of 'handle_config'.
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::Heap domain_registry_heap { env.ram(), env.rm() };
|
2016-12-01 17:37:08 +01:00
|
|
|
Genode::Reconstructible<Domain_registry> domain_registry {
|
2016-07-13 16:30:38 +02:00
|
|
|
domain_registry_heap, Genode::Xml_node("<config/>") };
|
2014-06-13 11:37:34 +02:00
|
|
|
|
2014-07-08 22:53:41 +02:00
|
|
|
User_state user_state = { global_keys, fb_screen->screen.size() };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create view stack with default elements
|
|
|
|
*/
|
2014-07-02 22:00:15 +02:00
|
|
|
Pointer_origin pointer_origin;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-09-22 11:09:02 +02:00
|
|
|
Background builtin_background = { Area(99999, 99999) };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize Nitpicker root interface
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::Sliced_heap sliced_heap { env.ram(), env.rm() };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-10-27 12:14:48 +02:00
|
|
|
Genode::Reporter pointer_reporter = { env, "pointer" };
|
|
|
|
Genode::Reporter hover_reporter = { env, "hover" };
|
|
|
|
Genode::Reporter focus_reporter = { env, "focus" };
|
|
|
|
Genode::Reporter keystate_reporter = { env, "keystate" };
|
2014-07-08 17:35:40 +02:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Genode::Attached_rom_dataspace config { env, "config" };
|
|
|
|
|
|
|
|
Root<PT> np_root = { env, config, session_list, *domain_registry,
|
|
|
|
global_keys, user_state, user_state, pointer_origin,
|
2017-09-22 11:09:02 +02:00
|
|
|
builtin_background, sliced_heap, framebuffer, focus_reporter };
|
2014-01-11 02:14:09 +01:00
|
|
|
|
2013-09-07 02:17:15 +02:00
|
|
|
/*
|
2016-07-13 16:30:38 +02:00
|
|
|
* Configuration-update handler, executed in the context of the RPC
|
2013-09-07 23:48:40 +02:00
|
|
|
* entrypoint.
|
|
|
|
*
|
2016-07-13 16:30:38 +02:00
|
|
|
* In addition to installing the signal handler, we trigger first signal
|
2013-09-07 23:48:40 +02:00
|
|
|
* manually to turn the initial configuration into effect.
|
2013-09-07 02:17:15 +02:00
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
void handle_config();
|
2013-09-07 02:17:15 +02:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Signal_handler<Main> config_handler = { env.ep(), *this, &Main::handle_config};
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2013-09-08 16:20:18 +02:00
|
|
|
/**
|
|
|
|
* Signal handler invoked on the reception of user input
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
void handle_input();
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Signal_handler<Main> input_handler = { env.ep(), *this, &Main::handle_input };
|
2013-09-07 02:17:15 +02:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/*
|
2014-04-30 13:51:45 +02:00
|
|
|
* Dispatch input and redraw periodically
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2017-01-02 14:10:33 +01:00
|
|
|
Timer::Connection timer { env };
|
2013-09-08 16:20:18 +02:00
|
|
|
|
2015-09-24 14:48:08 +02:00
|
|
|
/**
|
|
|
|
* Counter that is incremented periodically
|
|
|
|
*/
|
|
|
|
unsigned period_cnt = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Period counter when the user was active the last time
|
|
|
|
*/
|
|
|
|
unsigned last_active_period = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Number of periods after the last user activity when we regard the user
|
|
|
|
* as becoming inactive
|
|
|
|
*/
|
|
|
|
unsigned activity_threshold = 50;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* True if the user was recently active
|
|
|
|
*
|
|
|
|
* This state is reported as part of focus reports to allow the clipboard
|
|
|
|
* to dynamically adjust its information-flow policy to the user activity.
|
|
|
|
*/
|
|
|
|
bool user_active = false;
|
|
|
|
|
2014-07-25 14:22:03 +02:00
|
|
|
/**
|
|
|
|
* Perform redraw and flush pixels to the framebuffer
|
|
|
|
*/
|
|
|
|
void draw_and_flush()
|
|
|
|
{
|
|
|
|
user_state.draw(fb_screen->screen).flush([&] (Rect const &rect) {
|
|
|
|
framebuffer.refresh(rect.x1(), rect.y1(),
|
|
|
|
rect.w(), rect.h()); });
|
|
|
|
}
|
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
Main(Env &env) : env(env)
|
2013-09-07 23:48:40 +02:00
|
|
|
{
|
2017-09-22 11:09:02 +02:00
|
|
|
user_state.default_background(builtin_background);
|
2014-07-02 22:00:15 +02:00
|
|
|
user_state.stack(pointer_origin);
|
2017-09-22 11:09:02 +02:00
|
|
|
user_state.stack(builtin_background);
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
config.sigh(config_handler);
|
|
|
|
handle_config();
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
framebuffer.sync_sigh(input_handler);
|
|
|
|
framebuffer.mode_sigh(fb_mode_handler);
|
2014-02-11 15:11:31 +01:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
env.parent().announce(env.ep().manage(np_root));
|
2013-09-08 16:20:18 +02:00
|
|
|
}
|
|
|
|
};
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2013-09-07 02:17:15 +02:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
void Nitpicker::Main::handle_input()
|
2013-09-08 16:20:18 +02:00
|
|
|
{
|
2015-09-24 14:48:08 +02:00
|
|
|
period_cnt++;
|
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
Point const old_pointer_pos = user_state.pointer_pos();
|
|
|
|
::Session * const old_pointed_session = user_state.pointed_session();
|
|
|
|
::Session * const old_focused_session = user_state.Mode::focused_session();
|
|
|
|
bool const old_user_active = user_active;
|
2014-09-30 18:18:47 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* handle batch of pending events */
|
2017-10-27 12:14:48 +02:00
|
|
|
unsigned const num_events = input.flush();
|
|
|
|
if (import_input_events(ev_buf, num_events, user_state)) {
|
2015-09-30 11:30:02 +02:00
|
|
|
last_active_period = period_cnt;
|
|
|
|
user_active = true;
|
|
|
|
}
|
2014-01-11 02:14:09 +01:00
|
|
|
|
2017-10-27 12:14:48 +02:00
|
|
|
/*
|
|
|
|
* Report information about currently pressed keys whenever the key state
|
|
|
|
* is affected by the incoming events.
|
|
|
|
*/
|
|
|
|
if (keystate_reporter.enabled()) {
|
|
|
|
|
|
|
|
bool key_state_affected = false;
|
|
|
|
for (unsigned i = 0; i < num_events; i++)
|
|
|
|
key_state_affected |= (ev_buf[i].type() == Input::Event::PRESS) ||
|
|
|
|
(ev_buf[i].type() == Input::Event::RELEASE);
|
|
|
|
|
|
|
|
if (key_state_affected)
|
|
|
|
Genode::Reporter::Xml_generator xml(keystate_reporter, [&] () {
|
|
|
|
user_state.report_keystate(xml); });
|
|
|
|
}
|
|
|
|
|
2015-10-08 00:09:10 +02:00
|
|
|
user_state.Mode::apply_pending_focus_change();
|
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
Point const new_pointer_pos = user_state.pointer_pos();
|
|
|
|
::Session * const new_pointed_session = user_state.pointed_session();
|
|
|
|
::Session * const new_focused_session = user_state.Mode::focused_session();
|
2014-07-08 22:53:41 +02:00
|
|
|
|
2015-10-08 00:09:10 +02:00
|
|
|
if (old_focused_session != new_focused_session)
|
|
|
|
user_state.update_all_views();
|
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* flag user as inactive after activity threshold is reached */
|
|
|
|
if (period_cnt == last_active_period + activity_threshold)
|
|
|
|
user_active = false;
|
2014-07-08 22:53:41 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* report mouse-position updates */
|
2016-05-11 18:21:47 +02:00
|
|
|
if (pointer_reporter.enabled() && old_pointer_pos != new_pointer_pos) {
|
2015-09-30 11:30:02 +02:00
|
|
|
Genode::Reporter::Xml_generator xml(pointer_reporter, [&] ()
|
|
|
|
{
|
|
|
|
xml.attribute("xpos", new_pointer_pos.x());
|
|
|
|
xml.attribute("ypos", new_pointer_pos.y());
|
|
|
|
});
|
|
|
|
}
|
2014-07-08 22:53:41 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* report hover changes */
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!user_state.Mode::key_pressed()
|
2015-09-30 11:30:02 +02:00
|
|
|
&& old_pointed_session != new_pointed_session) {
|
|
|
|
report_session(hover_reporter, new_pointed_session);
|
|
|
|
}
|
2014-04-30 13:51:45 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* report focus changes */
|
|
|
|
if (old_focused_session != new_focused_session
|
|
|
|
|| old_user_active != user_active)
|
|
|
|
report_session(focus_reporter, new_focused_session, user_active);
|
2014-04-30 13:51:45 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* update mouse cursor */
|
|
|
|
if (old_pointer_pos != new_pointer_pos)
|
|
|
|
user_state.geometry(pointer_origin, Rect(new_pointer_pos, Area()));
|
2014-06-23 13:15:53 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* perform redraw and flush pixels to the framebuffer */
|
|
|
|
user_state.draw(fb_screen->screen).flush([&] (Rect const &rect) {
|
|
|
|
framebuffer.refresh(rect.x1(), rect.y1(),
|
|
|
|
rect.w(), rect.h()); });
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
user_state.mark_all_views_as_clean();
|
2013-09-07 23:48:40 +02:00
|
|
|
|
2015-09-30 11:30:02 +02:00
|
|
|
/* deliver framebuffer synchronization events */
|
|
|
|
for (::Session *s = session_list.first(); s; s = s->next())
|
|
|
|
s->submit_sync();
|
2013-09-08 16:20:18 +02:00
|
|
|
}
|
2013-09-07 23:48:40 +02:00
|
|
|
|
|
|
|
|
2014-09-30 18:18:47 +02:00
|
|
|
/**
|
|
|
|
* Helper function for 'handle_config'
|
|
|
|
*/
|
2016-07-13 16:30:38 +02:00
|
|
|
static void configure_reporter(Genode::Xml_node config, Genode::Reporter &reporter)
|
2014-09-30 18:18:47 +02:00
|
|
|
{
|
|
|
|
try {
|
2016-07-13 16:30:38 +02:00
|
|
|
reporter.enabled(config.sub_node("report")
|
|
|
|
.attribute_value(reporter.name().string(), false));
|
2014-09-30 18:18:47 +02:00
|
|
|
} catch (...) {
|
|
|
|
reporter.enabled(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
void Nitpicker::Main::handle_config()
|
2013-09-08 16:20:18 +02:00
|
|
|
{
|
2016-07-13 16:30:38 +02:00
|
|
|
config.update();
|
2013-09-09 22:39:54 +02:00
|
|
|
|
|
|
|
/* update global keys policy */
|
2016-07-13 16:30:38 +02:00
|
|
|
global_keys.apply_config(config.xml(), session_list);
|
2013-09-09 22:39:54 +02:00
|
|
|
|
|
|
|
/* update background color */
|
2013-09-08 16:20:18 +02:00
|
|
|
try {
|
2016-07-13 16:30:38 +02:00
|
|
|
config.xml().sub_node("background")
|
2017-09-22 11:09:02 +02:00
|
|
|
.attribute("color").value(&builtin_background.color);
|
2013-09-08 16:20:18 +02:00
|
|
|
} catch (...) { }
|
2013-09-09 22:39:54 +02:00
|
|
|
|
2015-06-04 16:32:49 +02:00
|
|
|
/* enable or disable redraw debug mode */
|
2016-07-13 16:30:38 +02:00
|
|
|
tmp_fb = config.xml().attribute_value("flash", false)
|
2016-06-09 15:55:13 +02:00
|
|
|
? &framebuffer
|
|
|
|
: nullptr;
|
2015-06-04 16:32:49 +02:00
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
configure_reporter(config.xml(), pointer_reporter);
|
|
|
|
configure_reporter(config.xml(), hover_reporter);
|
|
|
|
configure_reporter(config.xml(), focus_reporter);
|
2017-10-27 12:14:48 +02:00
|
|
|
configure_reporter(config.xml(), keystate_reporter);
|
2014-07-08 17:35:40 +02:00
|
|
|
|
2014-06-13 11:37:34 +02:00
|
|
|
/* update domain registry and session policies */
|
|
|
|
for (::Session *s = session_list.first(); s; s = s->next())
|
|
|
|
s->reset_domain();
|
|
|
|
|
|
|
|
try {
|
2016-07-13 16:30:38 +02:00
|
|
|
domain_registry.construct(domain_registry_heap, config.xml()); }
|
2014-06-13 11:37:34 +02:00
|
|
|
catch (...) { }
|
|
|
|
|
2013-09-09 22:39:54 +02:00
|
|
|
for (::Session *s = session_list.first(); s; s = s->next())
|
2016-07-13 16:30:38 +02:00
|
|
|
s->apply_session_policy(config.xml(), *domain_registry);
|
2013-09-09 22:39:54 +02:00
|
|
|
|
2014-07-02 22:00:15 +02:00
|
|
|
user_state.apply_origin_policy(pointer_origin);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Domains may have changed their layering, resort the view stack with the
|
|
|
|
* new constrains.
|
|
|
|
*/
|
|
|
|
user_state.sort_views_by_layer();
|
2014-07-02 17:37:02 +02:00
|
|
|
|
2013-09-09 22:39:54 +02:00
|
|
|
/* redraw */
|
2014-04-30 13:51:45 +02:00
|
|
|
user_state.update_all_views();
|
2017-11-01 14:45:10 +01:00
|
|
|
|
|
|
|
/* update focus report since the domain colors might have changed */
|
|
|
|
report_session(focus_reporter, user_state.Mode::focused_session(), user_active);
|
2014-02-11 15:11:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-13 16:30:38 +02:00
|
|
|
void Nitpicker::Main::handle_fb_mode()
|
2014-02-11 15:11:31 +01:00
|
|
|
{
|
|
|
|
/* reconstruct framebuffer screen and menu bar */
|
2017-01-02 14:10:33 +01:00
|
|
|
fb_screen.construct(env.rm(), framebuffer);
|
2014-02-11 15:11:31 +01:00
|
|
|
|
|
|
|
/* let the view stack use the new size */
|
|
|
|
user_state.size(Area(fb_screen->mode.width(), fb_screen->mode.height()));
|
|
|
|
|
|
|
|
/* redraw */
|
2014-04-30 13:51:45 +02:00
|
|
|
user_state.update_all_views();
|
2014-07-09 10:34:02 +02:00
|
|
|
|
|
|
|
/* notify clients about the change screen mode */
|
|
|
|
for (::Session *s = session_list.first(); s; s = s->next()) {
|
|
|
|
Session_component *sc = dynamic_cast<Session_component *>(s);
|
|
|
|
if (sc)
|
|
|
|
sc->notify_mode_change();
|
|
|
|
}
|
2013-09-08 16:20:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-15 15:40:55 +01:00
|
|
|
void Component::construct(Genode::Env &env)
|
|
|
|
{
|
|
|
|
/* XXX execute constructors of global statics */
|
|
|
|
env.exec_static_constructors();
|
|
|
|
|
|
|
|
static Nitpicker::Main nitpicker(env);
|
|
|
|
}
|