406 lines
11 KiB
C++
406 lines
11 KiB
C++
/*
|
|
* \brief Nitpicker session component
|
|
* \author Norman Feske
|
|
* \date 2017-11-16
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-2017 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 _SESSION_COMPONENT_H_
|
|
#define _SESSION_COMPONENT_H_
|
|
|
|
/* Genode includes */
|
|
#include <util/list.h>
|
|
#include <base/session_object.h>
|
|
#include <base/heap.h>
|
|
#include <os/session_policy.h>
|
|
#include <os/reporter.h>
|
|
#include <os/pixel_rgb565.h>
|
|
#include <nitpicker_session/nitpicker_session.h>
|
|
|
|
/* local includes */
|
|
#include "canvas.h"
|
|
#include "domain_registry.h"
|
|
#include "framebuffer_session.h"
|
|
#include "input_session.h"
|
|
#include "focus.h"
|
|
#include "chunky_texture.h"
|
|
#include "view_component.h"
|
|
|
|
namespace Nitpicker {
|
|
|
|
class Visibility_controller;
|
|
class Session_component;
|
|
class View_component;
|
|
|
|
typedef List<Session_component> Session_list;
|
|
}
|
|
|
|
|
|
struct Nitpicker::Visibility_controller : Interface
|
|
{
|
|
typedef Session::Label Suffix;
|
|
|
|
virtual void hide_matching_sessions(Session_label const &, Suffix const &) = 0;
|
|
|
|
virtual void show_matching_sessions(Session_label const &, Suffix const &) = 0;
|
|
};
|
|
|
|
|
|
class Nitpicker::Session_component : public Session_object<Nitpicker::Session>,
|
|
public View_owner,
|
|
public Buffer_provider,
|
|
private Session_list::Element
|
|
{
|
|
private:
|
|
|
|
friend class List<Session_component>;
|
|
|
|
using Nitpicker::Session::Label;
|
|
|
|
/*
|
|
* Noncopyable
|
|
*/
|
|
Session_component(Session_component const &);
|
|
Session_component &operator = (Session_component const &);
|
|
|
|
Env &_env;
|
|
|
|
Constrained_ram_allocator _ram;
|
|
|
|
Domain_registry::Entry const *_domain = nullptr;
|
|
Texture_base const *_texture = nullptr;
|
|
View_component *_background = nullptr;
|
|
|
|
/*
|
|
* The input mask buffer containing a byte value per texture pixel,
|
|
* which describes the policy of handling user input referring to the
|
|
* pixel. If set to zero, the input is passed through the view such
|
|
* that it can be handled by one of the subsequent views in the view
|
|
* stack. If set to one, the input is consumed by the view. If
|
|
* 'input_mask' is a null pointer, user input is unconditionally
|
|
* consumed by the view.
|
|
*/
|
|
unsigned char const *_input_mask = nullptr;
|
|
|
|
bool _uses_alpha = false;
|
|
bool _visible = true;
|
|
|
|
Sliced_heap _session_alloc;
|
|
|
|
Framebuffer::Session &_framebuffer;
|
|
|
|
Framebuffer::Session_component _framebuffer_session_component;
|
|
|
|
bool const _input_session_accounted = (
|
|
withdraw(Ram_quota{Input::Session_component::ev_ds_size()}), true );
|
|
|
|
Input::Session_component _input_session_component { _env };
|
|
|
|
View_stack &_view_stack;
|
|
|
|
Font const &_font;
|
|
|
|
Focus_updater &_focus_updater;
|
|
|
|
Signal_context_capability _mode_sigh { };
|
|
|
|
View_component &_pointer_origin;
|
|
|
|
View_component &_builtin_background;
|
|
|
|
List<Session_view_list_elem> _view_list { };
|
|
|
|
Tslab<View_component, 4000> _view_alloc { &_session_alloc };
|
|
|
|
/* capabilities for sub sessions */
|
|
Framebuffer::Session_capability _framebuffer_session_cap;
|
|
Input::Session_capability _input_session_cap;
|
|
|
|
bool const _provides_default_bg;
|
|
|
|
/* size of currently allocated virtual framebuffer, in bytes */
|
|
size_t _buffer_size = 0;
|
|
|
|
Attached_ram_dataspace _command_ds { _env.ram(), _env.rm(),
|
|
sizeof(Command_buffer) };
|
|
|
|
bool const _command_buffer_accounted = (
|
|
withdraw(Ram_quota{align_addr(sizeof(Session::Command_buffer), 12)}), true );
|
|
|
|
Command_buffer &_command_buffer = *_command_ds.local_addr<Command_buffer>();
|
|
|
|
typedef Handle_registry<View_handle, View_component> View_handle_registry;
|
|
|
|
View_handle_registry _view_handle_registry;
|
|
|
|
Reporter &_focus_reporter;
|
|
|
|
Visibility_controller &_visibility_controller;
|
|
|
|
Session_component *_forwarded_focus = nullptr;
|
|
|
|
/**
|
|
* Calculate session-local coordinate to physical screen position
|
|
*
|
|
* \param pos coordinate in session-local coordinate system
|
|
* \param screen_area session-local screen size
|
|
*/
|
|
Point _phys_pos(Point pos, Area screen_area) const
|
|
{
|
|
return _domain ? _domain->phys_pos(pos, screen_area) : Point(0, 0);
|
|
}
|
|
|
|
void _release_buffer();
|
|
|
|
/**
|
|
* 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, View_handle);
|
|
|
|
void _execute_command(Command const &);
|
|
|
|
void _destroy_view(View_component &);
|
|
|
|
public:
|
|
|
|
Session_component(Env &env,
|
|
Resources const &resources,
|
|
Label const &label,
|
|
Diag const &diag,
|
|
View_stack &view_stack,
|
|
Font const &font,
|
|
Focus_updater &focus_updater,
|
|
View_component &pointer_origin,
|
|
View_component &builtin_background,
|
|
Framebuffer::Session &framebuffer,
|
|
bool provides_default_bg,
|
|
Reporter &focus_reporter,
|
|
Visibility_controller &visibility_controller)
|
|
:
|
|
Session_object(env.ep(), resources, label, diag),
|
|
_env(env),
|
|
_ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()),
|
|
_session_alloc(_ram, env.rm()),
|
|
_framebuffer(framebuffer),
|
|
_framebuffer_session_component(view_stack, *this, framebuffer, *this),
|
|
_view_stack(view_stack), _font(font), _focus_updater(focus_updater),
|
|
_pointer_origin(pointer_origin),
|
|
_builtin_background(builtin_background),
|
|
_framebuffer_session_cap(_env.ep().manage(_framebuffer_session_component)),
|
|
_input_session_cap(_env.ep().manage(_input_session_component)),
|
|
_provides_default_bg(provides_default_bg),
|
|
_view_handle_registry(_session_alloc),
|
|
_focus_reporter(focus_reporter),
|
|
_visibility_controller(visibility_controller)
|
|
{ }
|
|
|
|
~Session_component()
|
|
{
|
|
_env.ep().dissolve(_framebuffer_session_component);
|
|
_env.ep().dissolve(_input_session_component);
|
|
|
|
destroy_all_views();
|
|
|
|
_release_buffer();
|
|
}
|
|
|
|
using Session_list::Element::next;
|
|
|
|
|
|
/**************************
|
|
** View_owner interface **
|
|
**************************/
|
|
|
|
Session::Label label() const override { return _label; }
|
|
|
|
/**
|
|
* Return true if session label starts with specified 'selector'
|
|
*/
|
|
bool matches_session_label(Session::Label const &selector) const override
|
|
{
|
|
/*
|
|
* Append label separator to match selectors with a trailing
|
|
* separator.
|
|
*/
|
|
String<Session_label::capacity() + 4> const label(_label, " ->");
|
|
return strcmp(label.string(), selector.string(),
|
|
strlen(selector.string())) == 0;
|
|
}
|
|
|
|
bool visible() const override { return _visible; }
|
|
|
|
bool label_visible() const override
|
|
{
|
|
return !_domain || _domain->label_visible();
|
|
}
|
|
|
|
bool has_same_domain(View_owner const *owner) const override
|
|
{
|
|
if (!owner) return false;
|
|
return static_cast<Session_component const &>(*owner)._domain == _domain;
|
|
}
|
|
|
|
bool has_focusable_domain() const override
|
|
{
|
|
return _domain && (_domain->focus_click() || _domain->focus_transient());
|
|
}
|
|
|
|
bool has_transient_focusable_domain() const override
|
|
{
|
|
return _domain && _domain->focus_transient();
|
|
}
|
|
|
|
Color color() const override { return _domain ? _domain->color() : white(); }
|
|
|
|
bool content_client() const override { return _domain && _domain->content_client(); }
|
|
|
|
bool hover_always() const override { return _domain && _domain->hover_always(); }
|
|
|
|
View const *background() const override { return _background; }
|
|
|
|
Texture_base const *texture() const override { return _texture; }
|
|
|
|
bool uses_alpha() const override { return _texture && _uses_alpha; }
|
|
|
|
unsigned layer() const override { return _domain ? _domain->layer() : ~0UL; }
|
|
|
|
bool origin_pointer() const override { return _domain && _domain->origin_pointer(); }
|
|
|
|
/**
|
|
* Return input mask value at specified buffer position
|
|
*/
|
|
unsigned char input_mask_at(Point p) const override
|
|
{
|
|
if (!_input_mask || !_texture) return 0;
|
|
|
|
/* check boundaries */
|
|
if ((unsigned)p.x() >= _texture->size().w()
|
|
|| (unsigned)p.y() >= _texture->size().h())
|
|
return 0;
|
|
|
|
return _input_mask[p.y()*_texture->size().w() + p.x()];
|
|
}
|
|
|
|
void submit_input_event(Input::Event e) override;
|
|
|
|
void report(Xml_generator &xml) const override
|
|
{
|
|
xml.attribute("label", _label);
|
|
xml.attribute("color", String<32>(color()));
|
|
|
|
if (_domain)
|
|
xml.attribute("domain", _domain->name());
|
|
}
|
|
|
|
View_owner &forwarded_focus() override;
|
|
|
|
|
|
/****************************************
|
|
** Interface used by the main program **
|
|
****************************************/
|
|
|
|
/**
|
|
* Set the visibility of the views owned by the session
|
|
*/
|
|
void visible(bool visible) { _visible = visible; }
|
|
|
|
/**
|
|
* Return session-local screen area
|
|
*
|
|
* \param phys_pos size of physical screen
|
|
*/
|
|
Area screen_area(Area phys_area) const
|
|
{
|
|
return _domain ? _domain->screen_area(phys_area) : Area(0, 0);
|
|
}
|
|
|
|
void reset_domain() { _domain = nullptr; }
|
|
|
|
/**
|
|
* Set session domain according to the list of configured policies
|
|
*
|
|
* Select the policy that matches the label. If multiple policies
|
|
* match, select the one with the largest number of characters.
|
|
*/
|
|
void apply_session_policy(Xml_node config, Domain_registry const &);
|
|
|
|
void destroy_all_views();
|
|
|
|
/**
|
|
* Deliver mode-change signal to client
|
|
*/
|
|
void notify_mode_change()
|
|
{
|
|
if (_mode_sigh.valid())
|
|
Signal_transmitter(_mode_sigh).submit();
|
|
}
|
|
|
|
/**
|
|
* Deliver sync signal to the client's virtual frame buffer
|
|
*/
|
|
void submit_sync()
|
|
{
|
|
_framebuffer_session_component.submit_sync();
|
|
}
|
|
|
|
void forget(Session_component &session)
|
|
{
|
|
if (_forwarded_focus == &session)
|
|
_forwarded_focus = nullptr;
|
|
}
|
|
|
|
|
|
/*********************************
|
|
** Nitpicker session interface **
|
|
*********************************/
|
|
|
|
Framebuffer::Session_capability framebuffer_session() override {
|
|
return _framebuffer_session_cap; }
|
|
|
|
Input::Session_capability input_session() override {
|
|
return _input_session_cap; }
|
|
|
|
View_handle create_view(View_handle parent_handle) override;
|
|
|
|
void destroy_view(View_handle handle) override;
|
|
|
|
View_handle view_handle(View_capability view_cap, View_handle handle) override;
|
|
|
|
View_capability view_capability(View_handle handle) override;
|
|
|
|
void release_view_handle(View_handle handle) override;
|
|
|
|
Dataspace_capability command_dataspace() override { return _command_ds.cap(); }
|
|
|
|
void execute() override;
|
|
|
|
Framebuffer::Mode mode() override;
|
|
|
|
void mode_sigh(Signal_context_capability sigh) override { _mode_sigh = sigh; }
|
|
|
|
void buffer(Framebuffer::Mode mode, bool use_alpha) override;
|
|
|
|
void focus(Capability<Nitpicker::Session> session_cap) override;
|
|
|
|
void session_control(Label suffix, Session_control control) override;
|
|
|
|
|
|
/*******************************
|
|
** Buffer_provider interface **
|
|
*******************************/
|
|
|
|
Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) override;
|
|
};
|
|
|
|
#endif /* _SESSION_COMPONENT_H_ */
|