genode/os/src/server/nitpicker/main.cc

938 lines
24 KiB
C++
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief Nitpicker main program for Genode
* \author Norman Feske
* \date 2006-08-04
*/
/*
2013-01-10 21:44:47 +01:00
* Copyright (C) 2006-2013 Genode Labs GmbH
2011-12-22 16:19:25 +01:00
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include <base/sleep.h>
#include <base/printf.h>
#include <base/allocator_guard.h>
2011-12-22 16:19:25 +01:00
#include <os/attached_ram_dataspace.h>
#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_view/nitpicker_view.h>
#include <nitpicker_session/nitpicker_session.h>
#include <framebuffer_session/connection.h>
#include <nitpicker_gfx/pixel_rgb565.h>
#include <util/color.h>
2011-12-22 16:19:25 +01:00
#include <os/session_policy.h>
2013-09-08 16:20:18 +02:00
#include <os/server.h>
2011-12-22 16:19:25 +01:00
/* local includes */
#include "input.h"
2011-12-22 16:19:25 +01:00
#include "big_mouse.h"
#include "background.h"
#include "clip_guard.h"
#include "mouse_cursor.h"
#include "chunky_menubar.h"
namespace Input { using namespace Genode; }
namespace Input { class Session_component; }
namespace Framebuffer { using namespace Genode; }
namespace Framebuffer { class Session_component; }
2013-09-08 16:20:18 +02:00
namespace Nitpicker {
using namespace Genode;
class Session_component;
template <typename> class Root;
struct Main;
}
2011-12-22 16:19:25 +01:00
/***************
** Utilities **
***************/
/*
* Font initialization
*/
extern char _binary_default_tff_start;
Font default_font(&_binary_default_tff_start);
class Flush_merger
{
private:
Canvas::Rect _to_be_flushed = { Canvas::Point(), Canvas::Area() };
2011-12-22 16:19:25 +01:00
public:
bool defer = false;
2011-12-22 16:19:25 +01:00
Canvas::Rect to_be_flushed() const { return _to_be_flushed; }
2011-12-22 16:19:25 +01:00
void merge(Canvas::Rect rect)
2011-12-22 16:19:25 +01:00
{
if (_to_be_flushed.valid())
_to_be_flushed = Canvas::Rect::compound(_to_be_flushed, rect);
2011-12-22 16:19:25 +01:00
else
_to_be_flushed = rect;
}
void reset() { _to_be_flushed = Canvas::Rect(Canvas::Point(), Canvas::Area()); }
2011-12-22 16:19:25 +01:00
};
template <typename PT>
class Screen : public Chunky_canvas<PT>, public Flush_merger
{
protected:
virtual void _flush_pixels(Canvas::Rect rect) { merge(rect); }
2011-12-22 16:19:25 +01:00
public:
/**
* Constructor
*/
Screen(PT *base, Canvas::Area size) : Chunky_canvas<PT>(base, size) { }
2011-12-22 16:19:25 +01:00
};
class Buffer
{
private:
Canvas::Area _size;
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
*
* \throw Ram_session::Alloc_failed
* \throw Rm_session::Attach_failed
*/
Buffer(Canvas::Area size, Framebuffer::Mode::Format format, Genode::size_t bytes)
:
_size(size), _format(format),
2011-12-22 16:19:25 +01:00
_ram_ds(Genode::env()->ram_session(), bytes)
{ }
/**
* Accessors
*/
Genode::Ram_dataspace_capability ds_cap() const { return _ram_ds.cap(); }
Canvas::Area size() const { return _size; }
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
};
/**
* 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>
class Chunky_dataspace_texture : public Buffer, public Chunky_texture<PT>
{
private:
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
*/
unsigned char *_alpha_base(Canvas::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
*/
Chunky_dataspace_texture(Canvas::Area size, bool use_alpha)
:
Buffer(size, _format(), calc_num_bytes(size, use_alpha)),
2011-12-22 16:19:25 +01:00
Chunky_texture<PT>((PT *)local_addr(),
_alpha_base(size, use_alpha), size) { }
static Genode::size_t calc_num_bytes(Canvas::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()
{
if (!Chunky_texture<PT>::alpha()) return 0;
/* input-mask values come right after the alpha values */
return (unsigned char *)local_addr() + calc_num_bytes(*this, false)
+ Texture::w()*Texture::h();
}
};
/***********************
** Input sub session **
***********************/
class Input::Session_component : public Genode::Rpc_object<Session>
{
public:
2011-12-22 16:19:25 +01:00
enum { MAX_EVENTS = 200 };
2011-12-22 16:19:25 +01:00
static size_t ev_ds_size() {
return align_addr(MAX_EVENTS*sizeof(Event), 12); }
private:
2011-12-22 16:19:25 +01:00
/*
* Exported event buffer dataspace
*/
Attached_ram_dataspace _ev_ram_ds = { env()->ram_session(), ev_ds_size() };
2011-12-22 16:19:25 +01:00
/*
* Local event buffer that is copied
* to the exported event buffer when
* flush() gets called.
*/
Event _ev_buf[MAX_EVENTS];
unsigned _num_ev = 0;
2011-12-22 16:19:25 +01:00
public:
2011-12-22 16:19:25 +01: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
/* insert event into local event buffer */
_ev_buf[_num_ev++] = *ev;
}
2011-12-22 16:19:25 +01:00
/*****************************
** Input session interface **
*****************************/
2011-12-22 16:19:25 +01:00
Dataspace_capability dataspace() { return _ev_ram_ds.cap(); }
2011-12-22 16:19:25 +01:00
bool is_pending() const { return _num_ev > 0; }
2011-12-22 16:19:25 +01:00
int flush()
{
unsigned ev_cnt;
2011-12-22 16:19:25 +01: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
_num_ev = 0;
return ev_cnt;
}
};
2011-12-22 16:19:25 +01:00
/*****************************
** Framebuffer sub session **
*****************************/
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
{
private:
2011-12-22 16:19:25 +01:00
::Buffer *_buffer = 0;
View_stack &_view_stack;
::Session &_session;
Flush_merger &_flush_merger;
Framebuffer::Session &_framebuffer;
Buffer_provider &_buffer_provider;
Signal_context_capability _mode_sigh;
Framebuffer::Mode _mode;
bool _alpha = false;
2011-12-22 16:19:25 +01:00
public:
2011-12-22 16:19:25 +01:00
/**
* Constructor
*/
Session_component(View_stack &view_stack,
::Session &session,
Flush_merger &flush_merger,
Framebuffer::Session &framebuffer,
Buffer_provider &buffer_provider)
:
_view_stack(view_stack),
_session(session),
_flush_merger(flush_merger),
_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
if (_mode_sigh.valid())
Signal_transmitter(_mode_sigh).submit();
}
/************************************
** Framebuffer::Session interface **
************************************/
Dataspace_capability dataspace()
{
_buffer = _buffer_provider.realloc_buffer(_mode, _alpha);
return _buffer ? _buffer->ds_cap() : Ram_dataspace_capability();
}
void release() { }
2011-12-22 16:19:25 +01:00
Mode mode() const
{
return _mode;
}
void mode_sigh(Signal_context_capability mode_sigh)
{
_mode_sigh = mode_sigh;
}
2011-12-22 16:19:25 +01:00
void refresh(int x, int y, int w, int h)
{
_view_stack.update_session_views(_session,
Canvas::Rect(Canvas::Point(x, y),
Canvas::Area(w, h)));
/* flush dirty pixels to physical frame buffer */
if (_flush_merger.defer == false) {
Canvas::Rect r = _flush_merger.to_be_flushed();
_framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h());
_flush_merger.reset();
2011-12-22 16:19:25 +01:00
}
_flush_merger.defer = true;
}
};
2011-12-22 16:19:25 +01:00
class View_component : public Genode::List<View_component>::Element,
public Genode::Rpc_object<Nitpicker::View>
{
private:
typedef Genode::Rpc_entrypoint Rpc_entrypoint;
View_stack &_view_stack;
::View _view;
Rpc_entrypoint &_ep;
2011-12-22 16:19:25 +01:00
public:
/**
* Constructor
*/
2013-09-07 02:02:26 +02:00
View_component(::Session &session, View_stack &view_stack,
Rpc_entrypoint &ep):
2013-09-07 02:02:26 +02:00
_view_stack(view_stack),
_view(session,
session.stay_top() ? ::View::STAY_TOP : ::View::NOT_STAY_TOP,
::View::NOT_TRANSPARENT, ::View::NOT_BACKGROUND, Canvas::Rect()),
2013-09-07 02:02:26 +02:00
_ep(ep) { }
2011-12-22 16:19:25 +01:00
2013-09-07 02:02:26 +02:00
::View &view() { return _view; }
2011-12-22 16:19:25 +01:00
/******************************
** Nitpicker view interface **
******************************/
int viewport(int x, int y, int w, int h,
int buf_x, int buf_y, bool redraw)
{
/* transpose y position by vertical session offset */
2013-09-07 02:02:26 +02:00
y += _view.session().v_offset();
2011-12-22 16:19:25 +01:00
_view_stack.viewport(_view, Canvas::Rect(Canvas::Point(x, y),
Canvas::Area(w, h)),
Canvas::Point(buf_x, buf_y), redraw);
2011-12-22 16:19:25 +01:00
return 0;
}
int stack(Nitpicker::View_capability neighbor_cap, bool behind, bool redraw)
{
using namespace Genode;
Object_pool<View_component>::Guard nvc(_ep.lookup_and_lock(neighbor_cap));
2011-12-22 16:19:25 +01:00
2013-09-07 02:02:26 +02:00
::View *neighbor_view = nvc ? &nvc->view() : 0;
2011-12-22 16:19:25 +01:00
2013-09-07 02:02:26 +02:00
_view_stack.stack(_view, neighbor_view, behind, redraw);
2011-12-22 16:19:25 +01:00
return 0;
}
int title(Title const &title)
{
2013-09-07 02:02:26 +02:00
_view_stack.title(_view, title.string());
2011-12-22 16:19:25 +01:00
return 0;
}
};
/*****************************************
** Implementation of Nitpicker service **
*****************************************/
class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
public ::Session,
public Buffer_provider
{
private:
2011-12-22 16:19:25 +01:00
Allocator_guard _buffer_alloc;
Framebuffer::Session &_framebuffer;
/* Framebuffer_session_component */
Framebuffer::Session_component _framebuffer_session_component;
2011-12-22 16:19:25 +01:00
/* Input_session_component */
Input::Session_component _input_session_component;
2011-12-22 16:19:25 +01:00
/*
* Entrypoint that is used for the views, input session,
* and framebuffer session.
*/
Rpc_entrypoint &_ep;
2011-12-22 16:19:25 +01:00
View_stack &_view_stack;
2011-12-22 16:19:25 +01:00
List<View_component> _view_list;
2011-12-22 16:19:25 +01: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
bool const _provides_default_bg;
2011-12-22 16:19:25 +01:00
/* size of currently allocated virtual framebuffer, in bytes */
size_t _buffer_size = 0;
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());
::Session::texture(0);
::Session::input_mask(0);
destroy(&_buffer_alloc, const_cast<Chunky_dataspace_texture<PT> *>(cdt));
_buffer_alloc.upgrade(_buffer_size);
_buffer_size = 0;
}
public:
2011-12-22 16:19:25 +01:00
/**
* Constructor
*/
Session_component(Session_label const &label,
View_stack &view_stack,
Rpc_entrypoint &ep,
Flush_merger &flush_merger,
Framebuffer::Session &framebuffer,
int v_offset,
bool provides_default_bg,
bool stay_top,
Allocator &buffer_alloc,
size_t ram_quota)
:
::Session(label, v_offset, stay_top),
_buffer_alloc(&buffer_alloc, ram_quota),
_framebuffer(framebuffer),
_framebuffer_session_component(view_stack, *this, flush_merger,
framebuffer, *this),
_ep(ep), _view_stack(view_stack),
_framebuffer_session_cap(_ep.manage(&_framebuffer_session_component)),
_input_session_cap(_ep.manage(&_input_session_component)),
_provides_default_bg(provides_default_bg)
{
_buffer_alloc.upgrade(ram_quota);
}
2011-12-22 16:19:25 +01:00
/**
* Destructor
*/
~Session_component()
{
_ep.dissolve(&_framebuffer_session_component);
_ep.dissolve(&_input_session_component);
2011-12-22 16:19:25 +01:00
while (View_component *vc = _view_list.first())
destroy_view(vc->cap());
_release_buffer();
}
2011-12-22 16:19:25 +01:00
void upgrade_ram_quota(size_t ram_quota) { _buffer_alloc.upgrade(ram_quota); }
2011-12-22 16:19:25 +01:00
/******************************************
** Nitpicker-internal session interface **
******************************************/
2011-12-22 16:19:25 +01:00
void submit_input_event(Input::Event e)
{
using namespace Input;
2011-12-22 16:19:25 +01:00
/*
* Transpose absolute coordinates by session-specific vertical
* offset.
*/
if (e.ax() || e.ay())
e = Event(e.type(), e.code(), e.ax(),
max(0, e.ay() - v_offset()), e.rx(), e.ry());
2011-12-22 16:19:25 +01:00
_input_session_component.submit(&e);
}
2011-12-22 16:19:25 +01:00
/*********************************
** Nitpicker session interface **
*********************************/
2011-12-22 16:19:25 +01:00
Framebuffer::Session_capability framebuffer_session() {
return _framebuffer_session_cap; }
2011-12-22 16:19:25 +01:00
Input::Session_capability input_session() {
return _input_session_cap; }
2011-12-22 16:19:25 +01:00
View_capability create_view()
{
/**
* FIXME: Do not allocate View meta data from Heap!
* Use a heap partition!
*/
View_component *view = new (env()->heap())
View_component(*this, _view_stack, _ep);
2011-12-22 16:19:25 +01:00
_view_list.insert(view);
return _ep.manage(view);
}
2011-12-22 16:19:25 +01:00
void destroy_view(View_capability view_cap)
{
View_component *vc = dynamic_cast<View_component *>(_ep.lookup_and_lock(view_cap));
if (!vc) return;
2011-12-22 16:19:25 +01:00
_view_stack.remove_view(vc->view());
_ep.dissolve(vc);
_view_list.remove(vc);
destroy(env()->heap(), vc);
}
2011-12-22 16:19:25 +01:00
int background(View_capability view_cap)
{
if (_provides_default_bg) {
Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap));
vc->view().background(true);
_view_stack.default_background(vc->view());
2011-12-22 16:19:25 +01:00
return 0;
}
/* revert old background view to normal mode */
if (::Session::background()) ::Session::background()->background(false);
2011-12-22 16:19:25 +01:00
/* assign session background */
Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap));
::Session::background(&vc->view());
2011-12-22 16:19:25 +01:00
/* switch background view to background mode */
if (::Session::background()) vc->view().background(true);
2011-12-22 16:19:25 +01:00
return 0;
}
Framebuffer::Mode mode()
{
unsigned const width = _framebuffer.mode().width();
unsigned const height = _framebuffer.mode().height()
- ::Session::v_offset();
return Framebuffer::Mode(width, height,
_framebuffer.mode().format());
}
void buffer(Framebuffer::Mode mode, bool use_alpha)
{
/* check if the session quota suffices for the specified mode */
if (_buffer_alloc.quota() < ram_quota(mode, use_alpha))
throw Nitpicker::Session::Out_of_metadata();
_framebuffer_session_component.notify_mode_change(mode, use_alpha);
}
/*******************************
** Buffer_provider interface **
*******************************/
Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha)
{
_release_buffer();
Canvas::Area const size(mode.width(), mode.height());
typedef Pixel_rgb565 PT;
_buffer_size =
Chunky_dataspace_texture<PT>::calc_num_bytes(size, use_alpha);
Chunky_dataspace_texture<PT> * const texture =
new (&_buffer_alloc) Chunky_dataspace_texture<PT>(size, use_alpha);
if (!_buffer_alloc.withdraw(_buffer_size)) {
destroy(&_buffer_alloc, texture);
_buffer_size = 0;
return 0;
}
::Session::texture(texture);
::Session::input_mask(texture->input_mask_buffer());
return texture;
}
};
2011-12-22 16:19:25 +01:00
template <typename PT>
class Nitpicker::Root : public Genode::Root_component<Session_component>
{
private:
2011-12-22 16:19:25 +01:00
Session_list &_session_list;
Global_keys &_global_keys;
Framebuffer::Mode _scr_mode;
View_stack &_view_stack;
Flush_merger &_flush_merger;
Framebuffer::Session &_framebuffer;
int _default_v_offset;
2011-12-22 16:19:25 +01:00
protected:
2011-12-22 16:19:25 +01:00
Session_component *_create_session(const char *args)
{
PINF("create session with args: %s\n", args);
size_t const ram_quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0);
2011-12-22 16:19:25 +01:00
int const v_offset = _default_v_offset;
2011-12-22 16:19:25 +01:00
bool const stay_top = Arg_string::find_arg(args, "stay_top").bool_value(false);
2011-12-22 16:19:25 +01:00
size_t const required_quota = Input::Session_component::ev_ds_size();
2013-09-06 17:34:16 +02:00
if (ram_quota < required_quota) {
PWRN("Insufficient dontated ram_quota (%zd bytes), require %zd bytes",
ram_quota, required_quota);
throw Root::Quota_exceeded();
2011-12-22 16:19:25 +01:00
}
size_t const unused_quota = ram_quota - required_quota;
2013-09-06 17:34:16 +02:00
Session_label const label(args);
bool const provides_default_bg = (strcmp(label.string(), "backdrop") == 0);
2013-09-07 02:02:26 +02:00
Session_component *session = new (md_alloc())
Session_component(Session_label(args), _view_stack, *ep(),
_flush_merger, _framebuffer, v_offset,
provides_default_bg, stay_top,
*md_alloc(), unused_quota);
2011-12-22 16:19:25 +01:00
session->apply_session_color();
_session_list.insert(session);
_global_keys.apply_config(_session_list);
2011-12-22 16:19:25 +01:00
return session;
}
2011-12-22 16:19:25 +01:00
void _upgrade_session(Session_component *s, const char *args)
{
size_t ram_quota = Arg_string::find_arg(args, "ram_quota").long_value(0);
s->upgrade_ram_quota(ram_quota);
}
2011-12-22 16:19:25 +01:00
void _destroy_session(Session_component *session)
{
_session_list.remove(session);
_global_keys.apply_config(_session_list);
2011-12-22 16:19:25 +01:00
destroy(md_alloc(), session);
}
2011-12-22 16:19:25 +01:00
public:
/**
* Constructor
*/
Root(Session_list &session_list, Global_keys &global_keys,
Rpc_entrypoint &session_ep, View_stack &view_stack,
Allocator &md_alloc, Flush_merger &flush_merger,
Framebuffer::Session &framebuffer, int default_v_offset)
2011-12-22 16:19:25 +01:00
:
Root_component<Session_component>(&session_ep, &md_alloc),
_session_list(session_list), _global_keys(global_keys),
_view_stack(view_stack), _flush_merger(flush_merger),
_framebuffer(framebuffer), _default_v_offset(default_v_offset)
{ }
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
{
2013-09-08 16:20:18 +02:00
Server::Entrypoint &ep;
2011-12-22 16:19:25 +01:00
/*
* Sessions to the required external services
*/
2013-09-08 16:20:18 +02:00
Framebuffer::Connection framebuffer;
Input::Connection input;
2011-12-22 16:19:25 +01:00
2013-09-08 16:20:18 +02:00
Input::Event * const ev_buf =
env()->rm_session()->attach(input.dataspace());
2011-12-22 16:19:25 +01:00
/*
* Initialize framebuffer
*/
Framebuffer::Mode const mode = framebuffer.mode();
2011-12-22 16:19:25 +01:00
Dataspace_capability fb_ds_cap = framebuffer.dataspace();
2013-09-08 16:20:18 +02:00
typedef Pixel_rgb565 PT; /* physical pixel type */
2011-12-22 16:19:25 +01:00
void *fb_base = env()->rm_session()->attach(fb_ds_cap);
Screen<PT> screen = { (PT *)fb_base, Canvas::Area(mode.width(), mode.height()) };
2013-09-08 16:20:18 +02:00
/*
* Menu bar
*/
2011-12-22 16:19:25 +01:00
enum { MENUBAR_HEIGHT = 16 };
2013-09-08 16:20:18 +02:00
PT *menubar_pixels = (PT *)env()->heap()->alloc(sizeof(PT)*mode.width()*16);
2011-12-22 16:19:25 +01:00
Chunky_menubar<PT> menubar = { menubar_pixels, Canvas::Area(mode.width(), MENUBAR_HEIGHT) };
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
2013-09-08 16:20:18 +02:00
User_state user_state = { global_keys, screen, menubar };
2011-12-22 16:19:25 +01:00
/*
* Create view stack with default elements
*/
Canvas::Area mouse_size { big_mouse.w, big_mouse.h };
2013-09-08 16:20:18 +02:00
Mouse_cursor<PT> mouse_cursor { (PT *)&big_mouse.pixels[0][0],
mouse_size, user_state };
2011-12-22 16:19:25 +01:00
2013-09-08 16:20:18 +02:00
Background background = { screen.size() };
2011-12-22 16:19:25 +01:00
/*
* Initialize Nitpicker root interface
*/
2013-09-08 16:20:18 +02:00
Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() };
2011-12-22 16:19:25 +01:00
2013-09-08 16:20:18 +02:00
Root<PT> np_root = { session_list, global_keys, ep.rpc_ep(),
user_state, sliced_heap, screen,
framebuffer, MENUBAR_HEIGHT };
2013-09-07 02:17:15 +02:00
/*
* Configuration-update dispatcher, executed in the context of the RPC
* entrypoint.
*
* In addition to installing the signal dispatcher, we trigger first signal
* manually to turn the initial configuration into effect.
2013-09-07 02:17:15 +02:00
*/
2013-09-08 16:20:18 +02:00
void handle_config(unsigned);
2013-09-07 02:17:15 +02:00
Signal_rpc_member<Main> config_dispatcher = { ep, *this, &Main::handle_config};
2013-09-08 16:20:18 +02:00
/**
* Signal handler invoked on the reception of user input
*/
void handle_input(unsigned);
Signal_rpc_member<Main> input_dispatcher = { ep, *this, &Main::handle_input };
2013-09-07 02:17:15 +02:00
2011-12-22 16:19:25 +01:00
/*
2013-09-08 16:20:18 +02:00
* Dispatch input on periodic timer signals every 10 milliseconds
2011-12-22 16:19:25 +01:00
*/
2013-09-08 16:20:18 +02:00
Timer::Connection timer;
Main(Server::Entrypoint &ep) : ep(ep)
{
2013-09-08 16:20:18 +02:00
menubar.state(user_state, "", "", BLACK);
2013-09-08 16:20:18 +02:00
user_state.default_background(background);
user_state.stack(mouse_cursor);
user_state.stack(menubar);
user_state.stack(background);
config()->sigh(config_dispatcher);
Signal_transmitter(config_dispatcher).submit();
timer.sigh(input_dispatcher);
2013-09-08 16:20:18 +02:00
timer.trigger_periodic(10*1000);
2013-09-08 16:20:18 +02:00
env()->parent()->announce(ep.manage(np_root));
}
};
2013-09-07 02:17:15 +02:00
2013-09-08 16:20:18 +02:00
void Nitpicker::Main::handle_input(unsigned)
{
/*
* If kill mode is already active, we got recursively called from
* within this 'input_func' (via 'wait_and_dispatch_one_signal').
* In this case, return immediately. New input events will be
* processed in the local 'do' loop.
*/
if (user_state.kill())
return;
do {
Canvas::Point const old_mouse_pos = user_state.mouse_pos();
2013-09-08 16:20:18 +02:00
/* handle batch of pending events */
if (input.is_pending())
import_input_events(ev_buf, input.flush(), user_state);
Canvas::Point const new_mouse_pos = user_state.mouse_pos();
2013-09-08 16:20:18 +02:00
/* update mouse cursor */
if (old_mouse_pos != new_mouse_pos)
user_state.viewport(mouse_cursor,
Canvas::Rect(new_mouse_pos, mouse_size),
Canvas::Point(), true);
2013-09-08 16:20:18 +02:00
/* flush dirty pixels to physical frame buffer */
if (screen.defer == false) {
Canvas::Rect const r = screen.to_be_flushed();
2013-09-08 16:20:18 +02:00
if (r.valid())
framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h());
screen.reset();
}
screen.defer = false;
2013-09-08 16:20:18 +02:00
/*
* In kill mode, we do not leave the dispatch function in order to
* block RPC calls from Nitpicker clients. We block for signals
* here to stay responsive to user input and configuration changes.
* Nested calls of 'input_func' are prevented by the condition
* check for 'user_state.kill()' at the beginning of the handler.
*/
if (user_state.kill())
Server::wait_and_dispatch_one_signal();
2013-09-08 16:20:18 +02:00
} while (user_state.kill());
}
2013-09-08 16:20:18 +02:00
void Nitpicker::Main::handle_config(unsigned)
{
config()->reload();
/* update global keys policy */
2013-09-08 16:20:18 +02:00
global_keys.apply_config(session_list);
/* update background color */
2013-09-08 16:20:18 +02:00
try {
config()->xml_node().sub_node("background")
.attribute("color").value(&background.color);
} catch (...) { }
/* update session policies */
for (::Session *s = session_list.first(); s; s = s->next())
s->apply_session_color();
/* redraw */
2013-09-08 16:20:18 +02:00
user_state.update_all_views();
}
/************
** Server **
************/
2013-09-08 16:20:18 +02:00
namespace Server {
2011-12-22 16:19:25 +01:00
2013-09-08 16:20:18 +02:00
char const *name() { return "nitpicker_ep"; }
size_t stack_size() { return 4*1024*sizeof(long); }
void construct(Entrypoint &ep)
{
static Nitpicker::Main nitpicker(ep);
}
2011-12-22 16:19:25 +01:00
}