l4re-base-25.08.0

This commit is contained in:
2025-09-12 15:55:45 +02:00
commit d959eaab98
37938 changed files with 9382688 additions and 0 deletions

4
src/l4/pkg/mag/Control Normal file
View File

@@ -0,0 +1,4 @@
provides: libmag mag-input-libinput mag-input-event mag-client_fb mag-mag_client mag-session_manager
requires: l4re libc stdlibs-sh input l4util mag-gfx libstdc++
lua++
Maintainer: warg@os.inf.tu-dresden.de

10
src/l4/pkg/mag/Makefile Normal file
View File

@@ -0,0 +1,10 @@
PKGDIR ?= .
L4DIR ?= $(PKGDIR)/../..
TARGET = include plugins server lib
include $(L4DIR)/mk/subdir.mk
#server: tool
server: include
plugins: include
server: plugins

4
src/l4/pkg/mag/README Normal file
View File

@@ -0,0 +1,4 @@
* GUI -- nitpicker clone
* The files lua_glue.swg.h and lua_glue.swg.cc are generated by swig
(https://github.com/swig/swig) 4.0.0 pre release, commit
f8ffc04215b1be9ade91d418c0e0cf309e1809a2.

View File

@@ -0,0 +1 @@
INPUT += %PKGDIR%/doc/mag.dox

118
src/l4/pkg/mag/doc/mag.dox Normal file
View File

@@ -0,0 +1,118 @@
// vi:ft=c
/**
* \page l4re_servers L4Re Servers
*
* - \subpage l4re_servers_mag
*
* Our default multiplexer for the graphics hardware is Mag. Mag is a
* Nitpicker (TODO: ref) derivate that allows secure multiplexing of
* the graphics and input hardware among multiple applications and multiple
* complete windowing environments.
*
* \page l4re_servers_mag Mag, the GUI Multiplexer
*
* Mag is the default multiplexer for graphics hardware. It is not, and does
* not attempt to be, a fully-fledged window manager.
*
* Command Line Options
* --------------------
* As Mag's only command line option it supports loading additional plugins via
* the application's command line. Plugins must be either a Lua file or a
* shared library. Shared libraries must be named `libmag-$LIBNAME.so`.
*
* Mag Sessions
* ------------
* Mag provides two types of sessions which a client can create via the Factory
* interface.
*
* 1. Mag client session
*
* A client with a mag client session gets access to the whole screen. The
* client has to allocate and manage it's own buffers and has to position
* them on the screen on its own. Mag provides the factory to create client
* sessions via the capability named `mag`.
*
* 2. Client framebuffer session
*
* For a client framebuffer session mag allocates a view of the requested
* size and displays it at the requested coordinates on the screen. Mag
* provides the factory to create framebuffer sessions via the capability
* named `svc`.
*
* The options described below are options the client provides to the
* L4::Factory::create() call. These options influence the appearance and
* behaviour of the newly created session.
*
* ### Session Factory Options ###
* As a simple nitpicker clone Mag supports the so-called Xray mode. This mode
* displays all session labels and draws a colored frame around them. The
* session that currently has the input focus is highlighted. The Xray mode is
* actived via the special keys _Scroll_ or _NEXTSONG_.
*
* Mag allows to define a text label and a color for all client session types.
* The label and the color are displayed when Mag enters the Xray mode.
*
* - Label Option: **label**
*
* `l=LABEL`, `label=LABEL` Set the session's text label to LABEL. The
* label is restricted to a length of 256 characters.
*
* - Color Option: **col**
*
* `col=COLOR` Set the session's color which is used in Xray mode to tint
* the session's screen area and the border drawn around it. The argument can
* be either one of the following letters or a hexdecimal representation of
* the RGB values.
*
* + `r, R` Red color
* + `g, G` Green color
* + `b, B` Blue color
* + `w, W` White color
* + `y, Y` Yellow color
* + `v, V` Magenta color
*
* Example
*
* -- set label to "Linux" and use a light blue color
* fb = mag_client:create(L4.Proto.Goos, "l=Linux", "col=98d9ff");
*
* ### Mag Client Session Options ###
* These options only apply to Mag client sessions.
*
* - Default Background Option: **default-background**
*
* `dfl-bg`, `default-background` Marks this session as the default
* background.
*
* ### Mag Client Framebuffer Session Options ###
* These options only apply to Mag client framebuffer sessions.
*
* - Geometry Option: **geometry**
*
* `g=GEOMETRY`, `geometry=GEOMETRY` Set the session's geometry and
* position on the screen. GEOMETRY is provided in an X11-style format, e.g.
* `g=WIDTHxHEIGHT+X_OFFSET+Y_OFFSET`.
*
* - Focus Option: **focus**
*
* `focus` Set the focus to this session.
*
* - Collapsed Option: **shaded**
*
* `shaded` The window is collapsed and only the title bar is visible. The
* window can be expanded by clicking into the title bar with the middle
* mouse button. Collapsing and expanding works also independently of this
* option.
*
* - Fixed Option: **fixed**
* `fixed` The window cannot be moved on the screen.
*
* - Barheight Option: **barheight**
*
* `barheight=X` Set the height of the title bar in pixels.
*
* Example
*
* -- create a window of 640x480 pixels at position (100,100) on the screen.
* fb = mag_fb:create(L4.Proto.Goos, "g=640x480+100+100");
*/

View File

@@ -0,0 +1,20 @@
PKGDIR ?= ..
L4DIR ?= $(PKGDIR)/../..
EXTRA_TARGET := \
server/factory \
server/menu \
server/mode \
server/plugin \
server/session \
server/user_state \
server/view \
server/view_stack \
server/input_driver \
server/input_source \
server/object \
server/valuator \
server/hid_report \
include $(L4DIR)/mk/include.mk

View File

@@ -0,0 +1,36 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag-gfx/canvas>
#include <l4/mag-gfx/factory>
#include <l4/re/video/goos>
namespace Mag_gfx {
class Texture;
}
namespace Mag_server {
using namespace Mag_gfx;
class View;
class Screen_factory : public virtual Factory
{
public:
virtual View *create_cursor(Texture const *cursor) = 0;
virtual ~Screen_factory() {}
};
}

View File

@@ -0,0 +1,275 @@
// vi:ft=cpp
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag/server/valuator>
namespace Mag_server {
class Axis_info
{
public:
int value;
int min;
int max;
int fuzz;
int flat;
int resolution;
int delta;
int mode;
};
class Axis_info_vector
{
public:
Axis_info_vector() : _i(0), _size(0) {}
explicit Axis_info_vector(unsigned size)
: _i(new Axis_info*[size]), _size(size)
{
for (unsigned i = 0; i < _size; ++i)
_i[i] = 0;
}
~Axis_info_vector()
{
if (!_i)
return;
for (unsigned i = 0; i < _size; ++i)
if (_i[i])
delete _i[i];
delete [] _i;
}
unsigned size() const { return _size; }
Axis_info const *get(unsigned idx) const
{
if (idx < _size)
return _i[idx];
return 0;
}
Axis_info *get(unsigned idx)
{
if (idx < _size )
return _i[idx];
return 0;
}
Axis_info *create(unsigned idx)
{
if (idx >= _size)
return 0;
if (_i[idx])
delete _i[idx];
_i[idx] = new Axis_info();
return _i[idx];
}
bool set(unsigned idx, Axis_info *info)
{
if (idx >= _size)
{
delete info;
return 0;
}
if (_i[idx])
delete _i[idx];
_i[idx] = info;
return true;
}
private:
Axis_info **_i;
unsigned _size;
Axis_info_vector(Axis_info_vector const &);
};
class Hid_report
{
public:
struct Key_event
{
int code;
int value;
};
Hid_report(l4_umword_t device_id, unsigned rels, unsigned abss, unsigned mscs,
unsigned sws, unsigned mts);
~Hid_report();
bool get(unsigned char type, unsigned code, int &val) const;
void set(unsigned char type, unsigned code, int val);
bool mt_get(unsigned id, unsigned code, int &val) const;
void mt_set(unsigned code, int val);
bool submit_mt();
Mag_server::Valuator<int> const *get_vals(unsigned char type) const;
Mag_server::Valuator<int> *get_vals(unsigned char type);
Mag_server::Valuator<int> const *get_mt_vals(unsigned id) const;
bool add_key(int code, int value);
Key_event const *get_key_event(unsigned idx) const;
Key_event const *find_key_event(int code) const;
void remove_key_event(int code);
void sync(long long time) { _time = time; }
long long time() const { return _time; }
void clear();
l4_umword_t device_id() const { return _device_id; }
Axis_info_vector const *abs_infos() const
{ return _abs_info; }
Axis_info_vector *abs_infos()
{ return _abs_info; }
void set_abs_info(Axis_info_vector *i)
{ _abs_info = i; }
private:
enum
{
Type_offset = 2,
Num_types = 4,
Mt_val_offset = 0x2f,
Num_mt_vals = 13,
Num_key_events = 5,
};
long long _time;
l4_umword_t const _device_id;
unsigned _kevs;
Key_event _kev[Num_key_events];
Valuator<int> _vals[Num_types];
unsigned _mts;
Valuator<int> *_mt;
Axis_info_vector *_abs_info;
};
struct Axis_xfrm_noop
{
void operator () (unsigned, int &) const {}
};
template<typename SINK, typename XFRM>
bool post_hid_report(Hid_report const *e, SINK &sink, XFRM const &xfrm_abs)
{
bool events = false;
bool trigger = false;
typename SINK::Event ne;
ne.time = e->time();
ne.payload.stream_id = e->device_id();
ne.payload.type = 2;
Valuator<int> const *v = e->get_vals(2);
for (unsigned i = 0; v && i < v->size(); ++i)
{
Value<int> val = v->get(i);
if (!val.valid())
continue;
ne.payload.code = i;
ne.payload.value = val.val();
trigger |= sink.put(ne);
events = true;
}
v = e->get_vals(3);
ne.payload.type = 3;
for (unsigned i = 0; v && i < v->size(); ++i)
{
Value<int> val = v->get(i);
if (!val.valid())
continue;
ne.payload.code = i;
ne.payload.value = val.val();
xfrm_abs(i, ne.payload.value);
trigger |= sink.put(ne);
events = true;
}
ne.payload.type = 1;
for (unsigned i = 0;; ++i)
{
Hid_report::Key_event const *ke = e->get_key_event(i);
if (!ke)
break;
ne.payload.code = ke->code;
ne.payload.value = ke->value;
trigger |= sink.put(ne);
events = true;
}
for (unsigned mt = 0; mt < 10; ++mt)
{
Valuator<int> const *m = e->get_mt_vals(mt);
if (!m)
continue;
bool mt_ev = false;
ne.payload.type = 3;
unsigned mt_offset = m->offset();
for (unsigned i = 0; i < m->size(); ++i)
{
Value<int> v = m->get(i + mt_offset);
if (!v.valid())
continue;
ne.payload.code = i + mt_offset;
ne.payload.value = v.val();
xfrm_abs(i + mt_offset, ne.payload.value);
trigger |= sink.put(ne);
events = true;
mt_ev = true;
}
if (mt_ev)
{
ne.payload.type = 0;
ne.payload.code = 2;
ne.payload.value = 0;
trigger |= sink.put(ne);
}
}
if (events)
{
ne.payload.type = 0;
ne.payload.code = 0;
ne.payload.value = 0;
trigger |= sink.put(ne);
}
return trigger;
}
}

View File

@@ -0,0 +1,159 @@
// vi:ft=cpp
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag/server/user_state>
#include <l4/mag/server/plugin>
#include <l4/re/event_enums.h>
namespace Mag_server {
template<int Max_axis>
class Motion_merger
{
private:
unsigned long _changed;
int _v[Max_axis];
enum Type
{
T_none = 0,
T_abs = 1,
T_rel = 2,
};
Type axis_inf(unsigned char axis) const
{ return Type((_changed >> (2*axis)) & 3); }
void set_axis_inf(unsigned char axis, Type t)
{ _changed |= ((unsigned long)t) << (axis*2); }
public:
Motion_merger() : _changed(0) {}
void reset() { _changed = 0; }
bool handle(User_state::Event const &e)
{
if (!(e.payload.type == L4RE_EV_REL || e.payload.type == L4RE_EV_ABS))
return false;
if (e.payload.code >= Max_axis)
return false;
unsigned char ax = e.payload.code;
if (axis_inf(ax) == T_none && e.payload.type == L4RE_EV_REL)
{
_v[ax] = 0;
set_axis_inf(ax, T_rel);
}
switch (e.payload.type)
{
case L4RE_EV_REL:
_v[ax] += e.payload.value;
break;
case L4RE_EV_ABS:
_v[ax] = e.payload.value;
set_axis_inf(ax, T_abs);
break;
}
return true;
}
bool set_event(unsigned char axis, User_state::Event *e)
{
unsigned i = axis_inf(axis);
if (!i)
return false;
if (i & T_abs)
e->payload.type = L4RE_EV_ABS;
else
e->payload.type = L4RE_EV_REL;
e->payload.code = axis;
e->payload.value = _v[axis];
return true;
}
template< typename I, typename T >
I merge(I const &s, I const &e, T *last_time)
{
for (I i = s; i != e; ++i)
if (handle(*i))
{
*last_time = i->time;
i->free();
}
else
return i;
return e;
}
template< typename E, typename I, typename F >
void process(I const &s, I const &end, F const &f)
{
for (I e = s; e != end; ++e)
{
E me;
me.payload.stream_id = e->payload.stream_id;
e = merge(e, end, &me.time);
for (unsigned i = 0; i < Max_axis; ++i)
if (set_event(i, &me))
f(me);
if (e != end)
{
reset();
f(*e);
}
else
break;
e->free();
}
}
};
class Motion_fwd
{
public:
template< /*typename E,*/ typename I, typename F >
void process(I const &s, I const &end, F const &f)
{
for (I e = s; e != end; ++e)
{
f(*e);
e->free();
}
}
};
class Input_driver : public Plugin
{
public:
explicit Input_driver(char const *name)
: Plugin(name)
{}
char const *type() const { return "input-driver"; }
virtual ~Input_driver() {}
};
}

View File

@@ -0,0 +1,47 @@
// vi:ft=cpp
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/re/event>
struct lua_State;
namespace Mag_server {
class Core_api;
class Input_source
{
public:
Input_source *_next_active;
void add_lua_input_source(lua_State *l);
protected:
Core_api *_core;
int _ref;
public:
typedef L4Re::Event_buffer::Event Event;
typedef L4Re::Event_stream_info Input_info;
typedef L4Re::Event_absinfo Input_absinfo;
explicit Input_source(Core_api *core = 0) : _core(core) {}
virtual void poll_events() = 0;
void post_event(Event const *e);
Input_source *next() const { return _next_active; }
virtual int get_stream_info(l4_umword_t stream_id, Input_info *info) = 0;
virtual int get_axis_info(l4_umword_t stream_id, unsigned naxes, unsigned *axes, Input_absinfo *info) = 0;
virtual ~Input_source() = 0;
};
inline Input_source::~Input_source() {}
}

View File

@@ -0,0 +1,381 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag-gfx/canvas>
#include <l4/mag-gfx/clip_guard>
#include <l4/mag-gfx/font>
#include <l4/cxx/observer>
#include <l4/re/event_enums.h>
namespace Mag_server {
template< typename C >
class Menu : private cxx::Observer
{
private:
typedef C Content;
typedef typename C::Value_type Item;
typedef typename C::Iterator Iterator;
typedef typename C::Const_iterator Const_iterator;
View *_view;
Core_api const *_core;
Content const *_content;
Const_iterator _current;
Area _size;
Area _cell;
int _height;
int _offset;
bool _scroll;
int _speed;
Font const *_font() const { return _core->label_font(); }
View_stack *_vstack() const { return _core->user_state()->vstack(); }
public:
int scroll_button_height() const { return 15; }
int item_sep() const { return 2; }
int menu_border() const { return 4; }
int min_width() const { return 180; }
Menu(Core_api const *core, View *view, Content const *content)
: _view(view), _core(core), _content(content), _current(content->end()),
_cell(min_width(), _font()->str_h("X") + 2 * item_sep()), _height(0),
_offset(0), _scroll(false), _speed(0)
{}
Area calc_geometry(Area const &size);
Const_iterator find(Point const &pos, Rect *cell, int *y);
bool find(Const_iterator const &x, Rect *cell, int *y);
void draw(Canvas *canvas, Point const &pos) const;
Const_iterator handle_event(Hid_report *e, Point const &mouse);
void scroll(int dist)
{
int h = _size.h() - 2 * scroll_button_height();
_offset = std::max(0, std::min(_height - h, _offset + dist));
}
void optimize_offset(int current_pos)
{
if (!_scroll)
{
_offset = 0;
return;
}
/* usable height */
int h = _size.h() - 2 * scroll_button_height();
int o_min = std::max(current_pos + _cell.h() - h, 0);
int o_max = std::min(current_pos, _height - h);
if (_offset <= o_max && _offset >= o_min)
return;
if (_offset > o_max)
_offset = o_max;
if (_offset < o_min)
_offset = o_min;
}
private:
template< typename F >
Const_iterator _find(Rect const &_bb, F const &f) const;
struct Find_for_pos
{
Point pos;
Rect *cell;
int *offs;
Find_for_pos(Point const &p, Rect *cell, int *offs)
: pos(p), cell(cell), offs(offs) {}
bool valid(Rect const &bb) const { return bb.contains(pos); }
bool operator () (Const_iterator const &, Rect const &bb, int y) const
{
if (!bb.contains(pos))
return false;
*cell = bb;
*offs = y;
return true;
}
};
struct Find_item
{
Const_iterator item;
Rect *cell;
int *offs;
Find_item(Const_iterator const &item, Rect *cell, int *offs)
: item(item), cell(cell), offs(offs) {}
bool valid(Rect const &) const { return true; }
bool operator () (Const_iterator const &e, Rect const &bb, int y) const
{
if (e != item)
return false;
*offs = y;
*cell = bb;
return true;
}
};
struct Draw_item
{
private:
Draw_item(Draw_item const &);
public:
Canvas *canvas;
Menu const *menu;
mutable Clip_guard g;
Draw_item(Menu const *m, Canvas *c) : canvas(c), menu(m) {}
bool valid(Rect const &bb) const
{
g.init(canvas, bb);
return canvas->clip_valid();
}
bool operator () (Const_iterator const &e, Rect br, int) const
{
Rgb32::Color lcol = e->ignore() ? Rgb32::Color(255, 200, 0) : Rgb32::White;
Rgb32::Color bcol = e == menu->_current ? Rgb32::Color(99, 120, 180) : Rgb32::Color(99, 99, 88);
canvas->draw_box(br, bcol);
br = br.offset(menu->menu_border(), menu->item_sep(), -menu->menu_border(), -menu->item_sep());
Clip_guard g(canvas, br);
canvas->draw_string(br.p1(), menu->_font(), lcol, e->label());
return false;
}
};
// handle timer ticks
void notify();
};
template<typename C>
Area
Menu<C>::calc_geometry(Area const &max_size)
{
Area fs(min_width(), 0); //2 * menu_border());
bool cf = _current == _content->end();
int cp = 0;
for (Const_iterator e = _content->begin(); e != _content->end(); ++e)
{
int w = _font()->str_w(e->label()) + 2 * menu_border();
if (w > fs.w())
fs.w(w);
if (_current == e)
{
cp = fs.h();
cf = true;
}
fs.h(fs.h() + _cell.h());
}
/* the current item is gone so select none */
if (!cf)
_current = _content->end();
_height = fs.h();
if (fs.h() > max_size.h())
{
fs.h(max_size.h());
_scroll = true;
}
else
_scroll = false;
if (_current != _content->end())
optimize_offset(cp);
if (fs.w() > max_size.w())
fs.w(max_size.w());
_cell.w(fs.w());
_size = fs;
return fs;
}
template< typename C >
template< typename F >
typename Menu<C>::Const_iterator
Menu<C>::_find(Rect const &_bb, F const &f) const
{
Rect bb = _bb;
if (_scroll)
bb = _bb.offset(0, scroll_button_height(), 0, -scroll_button_height());
if (!f.valid(bb))
return _content->end();
int y = 0;
for (Const_iterator e = _content->begin(); e != _content->end(); ++e)
{
int ny = y + _cell.h();
if (y - _offset > bb.h())
break;
if (ny >= _offset)
{
Rect br(Point(bb.x1(), bb.y1() + y - _offset), _cell);
if (f(e, br, y))
return e;
}
y = ny;
}
return _content->end();
}
template< typename C >
typename Menu<C>::Const_iterator
Menu<C>::find(Point const &pos, Rect *cell, int *y)
{ return _find(Rect(Point(), _size), Find_for_pos(pos, cell, y)); }
template< typename C >
bool
Menu<C>::find(Const_iterator const &x, Rect *cell, int *y)
{ return _find(Rect(Point(), _size), Find_item(x, cell, y)) != _content->end(); }
template< typename C >
void
Menu<C>::draw(Canvas *canvas, Point const &pos) const
{
using Mag_gfx::Clip_guard;
Rect bb(pos, _size);
Clip_guard g(canvas, bb);
if (!canvas->clip_valid())
return;
if (_scroll)
{
Rect s(pos, Area(_size.w(), scroll_button_height()));
canvas->draw_box(s, Rgb32::Color(99, 99, 88)); //, 220));
s = s + Point(0, _size.h() - scroll_button_height());
canvas->draw_box(s, Rgb32::Color(99, 99, 88)); //, 220));
}
// Hm, make g++ 4.2 happy, that tries to call the copy ctor
// in the case of directly using a temporary
Draw_item di(this, canvas);
_find(bb, di);
}
template< typename C >
typename Menu<C>::Const_iterator
Menu<C>::handle_event(Hid_report *e, Point const &mouse)
{
Valuator<int> const *abs = e->get_vals(3);
if (abs && abs->get(0).valid())
{
if (_scroll)
{
int const sbh = scroll_button_height();
int speed;
if ((speed = sbh - mouse.y()) > 0)
{
_speed = -speed;
if (!cxx::H_list<Observer>::in_list(this))
_core->get_ticks(this);
}
else if ((speed = sbh - (_size.h() - mouse.y())) > 0)
{
_speed = speed;
if (!cxx::H_list<Observer>::in_list(this))
_core->get_ticks(this);
}
else
{
cxx::H_list<Observer>::remove(this);
_speed = 0;
}
if (speed > 0)
return _content->end();
}
Rect nr;
int ny;
Const_iterator s = find(mouse, &nr, &ny);
if (_current != s)
{
Rect cr;
int cy;
bool refresh_cr = false;
if (_current != _content->end() && find(_current, &cr, &cy))
refresh_cr = true;
_current = s;
int old_offs = _offset;
if (_current != _content->end())
optimize_offset(ny);
if (old_offs != _offset)
_vstack()->refresh_view(_view, 0, *_view);
else
{
if (refresh_cr)
_vstack()->refresh_view(_view, 0, cr + _view->p1());
if (s != _content->end())
_vstack()->refresh_view(_view, 0, nr + _view->p1());
}
}
}
Hid_report::Key_event const *btn_left = e->find_key_event(L4RE_BTN_LEFT);
if (btn_left && btn_left->value == 0)
{
Rect nr;
int ny;
return find(mouse, &nr, &ny);
}
return _content->end();
}
template< typename C >
void
Menu<C>::notify()
{
if (!_speed)
cxx::H_list<Observer>::remove(this);
int old = _offset;
scroll(_speed);
if (old != _offset)
_vstack()->refresh_view(_view, 0, *_view);
else
cxx::H_list<Observer>::remove(this);
}
}

View File

@@ -0,0 +1,50 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
namespace Mag_server {
class Mode
{
private:
unsigned char _m;
public:
enum Mode_flag
{
Flat = 0,
X_ray = 1,
Kill = 2
};
Mode() : _m(Flat) {}
explicit Mode(unsigned char m) : _m(m) {}
Mode(Mode_flag m) : _m(m) {}
void toggle(Mode_flag m)
{
_m ^= m;
}
void set(Mode_flag m, bool on = true)
{
if (!on)
_m &= ~m;
else
_m |= m;
}
bool xray() const { return _m & X_ray; }
bool kill() const { return _m & Kill; }
bool flat() const { return _m == Flat; }
};
}

View File

@@ -0,0 +1,85 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/sys/cxx/ipc_epiface>
#include <l4/cxx/ref_ptr>
#include <l4/cxx/hlist>
#include <l4/re/util/object_registry>
#include <cassert>
namespace Mag_server {
class Object_gc;
class Object : public L4::Epiface, public cxx::H_list_item
{
private:
friend class Object_gc;
template< typename T >
friend class Gc_ref_count;
mutable int _ref_cnt;
void enqueue(cxx::H_list<Object> *q)
{
q->add(this);
}
public:
Object() : _ref_cnt(0)
{}
void add_ref() const throw() { ++_ref_cnt; }
int remove_ref() const throw() { return --_ref_cnt; }
virtual void destroy() = 0;
virtual ~Object() = 0;
};
inline Object::~Object() {}
class Registry : protected L4Re::Util::Object_registry
{
public:
Registry(L4::Ipc_svr::Server_iface *sif)
: L4Re::Util::Object_registry(sif)
{}
L4::Cap<void> register_obj(cxx::Ref_ptr<Object> o)
{
L4::Cap<void> r = L4Re::Util::Object_registry::register_obj(o.ptr());
if (r)
add_gc_obj(o.release());
return r;
}
L4::Cap<void> register_obj(cxx::Ref_ptr<Object> o, char const *name)
{
L4::Cap<void> r = L4Re::Util::Object_registry::register_obj(o.ptr(), name);
if (r)
add_gc_obj(o.release());
return r;
}
virtual void add_gc_obj(Object *o) = 0;
using L4Re::Util::Object_registry::dispatch;
using L4Re::Util::Object_registry::register_obj;
};
}

View File

@@ -0,0 +1,98 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag/server/object>
#include <l4/mag/server/session>
#include <l4/re/video/goos>
#include <l4/sys/cxx/ipc_varg>
#include <l4/cxx/hlist>
#include <l4/cxx/observer>
struct lua_State;
namespace Mag_gfx {
class Font;
}
namespace Mag_server {
class User_state;
class Input_source;
class Core_api
{
private:
User_state *_ust;
L4::Cap<L4Re::Video::Goos> _fb;
lua_State *_lua;
Mag_gfx::Font const *_label_font;
// not instanziatable
Core_api(Core_api const &);
void operator = (Core_api const &);
protected:
Core_api(lua_State *lua, User_state *u,
L4::Cap<L4Re::Video::Goos> fb, Mag_gfx::Font const *label_font);
public:
User_state *user_state() const { return _ust; }
L4::Cap<L4Re::Video::Goos> backend_fb() const { return _fb; }
Mag_gfx::Font const *label_font() const { return _label_font; }
lua_State *lua_state() const { return _lua; }
virtual Registry *registry() const = 0;
virtual void set_session_options(Session *s, L4::Ipc::Varg_list_ref ios,
Session::Property_handler const *extra = 0) const;
virtual void add_input_source(Input_source *i) = 0;
virtual void register_session(Session *) const = 0;
virtual Session_list *sessions() const = 0;
virtual void add_session_observer(cxx::Observer *) const = 0;
virtual void get_ticks(cxx::Observer *) const = 0;
};
class Plugin
{
private:
friend class Plugin_manager;
char const *const _name;
unsigned _flags;
Plugin *_next;
static Plugin *_first __attribute__((visibility("hidden")));
Plugin(Plugin const &);
void operator = (Plugin const &);
protected:
unsigned &get_flags() { return _flags; }
Plugin(char const *name) : _name(name), _flags(0), _next(_first)
{ _first = this; }
public:
enum Flag
{
F_started = 1
};
virtual char const *type() const { return "generic"; }
char const *name() const { return _name; }
bool started() const { return _flags & F_started; }
virtual void start(Core_api *) = 0;
virtual void stop() {}
virtual ~Plugin() {}
};
}

View File

@@ -0,0 +1,88 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag-gfx/gfx_colors>
#include <l4/cxx/string>
#include <l4/cxx/dlist>
#include <l4/cxx/observer>
namespace Mag_server {
class View;
class Session : public cxx::D_list_item
{
private:
unsigned _flags;
View *_bg;
Mag_gfx::Rgb32::Color _color;
char *_label;
cxx::Notifier *_ntfy;
protected:
void flags(unsigned setmask, unsigned clearmask)
{
_flags = (_flags & ~clearmask) | setmask;
}
public:
enum Flags
{
F_ignore = 0x01,
F_default_background = 0x02,
};
struct Property_handler
{
char const *tag;
bool value_property;
void (*handler)(Session *, Property_handler const *h, cxx::String const &value);
};
Session()
: _flags(0), _bg(0), _color(Mag_gfx::Rgb32::Black), _label(0), _ntfy(0)
{}
void set_notifier(cxx::Notifier *n) { _ntfy = n; }
bool ignore() const { return _flags & F_ignore; }
void ignore(bool ign)
{
if (ign)
_flags |= F_ignore;
else
_flags &= ~F_ignore;
}
unsigned flags() const { return _flags; }
char const *label() const { return _label; }
Mag_gfx::Rgb32::Color color() const { return _color; }
View *background() const { return _bg; }
void color(Mag_gfx::Rgb32::Color color) { _color = color; }
void background(View *bg) { _bg = bg; }
static void set_label_prop(Session *s, Property_handler const *, cxx::String const &v);
static void set_color_prop(Session *s, Property_handler const *, cxx::String const &v);
virtual void put_event(l4_umword_t stream, int type, int code, int value,
l4_uint64_t time) = 0;
virtual ~Session();
};
typedef cxx::D_list<Session> Session_list;
}

View File

@@ -0,0 +1,113 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag-gfx/geometry>
#include <l4/mag/server/view_stack>
#include <l4/re/video/view>
#include <l4/re/event>
#include <l4/mag/server/hid_report>
struct lua_State;
struct luaL_Reg;
namespace Mag_server {
using namespace Mag_gfx;
class User_state;
class View_proxy
{
private:
friend class User_state;
View_proxy(View_proxy const &);
void operator = (View_proxy const &);
View *_v;
View_proxy **_pn;
View_proxy *_n;
public:
explicit View_proxy(User_state *ust);
~View_proxy()
{
*_pn = _n;
_n->_pn = _pn;
}
View *view() const { return _v; }
void view(View *v) { _v = v; }
void forget(View *v) { if (_v == v) _v = 0; }
};
class User_state
{
public:
friend class View_proxy;
private:
View_stack *_vstack;
Point _mouse_pos;
View *_keyboard_focus;
View_proxy *_view_proxies;
View *_mouse_cursor;
lua_State *_l;
public:
static char const *const _class;
static luaL_Reg const _ops[];
User_state(lua_State *lua, View_stack *_vstack, View *cursor);
virtual ~User_state();
void forget_view(View *v);
View_stack *vstack() { return _vstack; }
View_stack const *vstack() const { return _vstack; }
void set_mode(Mode::Mode_flag m, bool on = true)
{ vstack()->set_mode(m, on); }
void toggle_mode(Mode::Mode_flag m)
{ vstack()->toggle_mode(m); }
bool set_focus(View *v);
View *kbd_focus() const { return _keyboard_focus; }
typedef L4Re::Event_buffer::Event Event;
typedef L4Re::Event_stream_info Input_info;
typedef L4Re::Event_absinfo Input_absinfo;
void set_pointer(int x, int y, bool hide);
void move_pointer(int x, int y)
{ set_pointer(_mouse_pos.x() + x, _mouse_pos.y() + y, false); }
Point const &mouse_pos() const { return _mouse_pos; }
int get_input_stream_info_for_id(l4_umword_t id, Input_info *info) const;
int get_input_axis_info(l4_umword_t id, unsigned naxes, unsigned const *axis,
Input_absinfo *info, unsigned char *ax_mode) const;
};
inline
View_proxy::View_proxy(User_state *ust)
: _v(0), _pn(&ust->_view_proxies), _n(ust->_view_proxies)
{
ust->_view_proxies = this;
if (_n)
_n->_pn = &_n;
}
}

View File

@@ -0,0 +1,174 @@
// vi:ft=cpp
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
namespace Mag_server {
template<typename V>
class Value
{
public:
Value() : _v(0) {}
Value(V v) : _v((v << 1) | 1) {}
Value(bool, V v) :_v(v) {}
void set(V v) { _v = (v << 1) | 1; }
void inv() { _v = 0; }
bool valid() const { return _v & 1; }
V val() const { return _v >> 1; }
private:
V _v;
};
template< typename V >
class Valuator
{
private:
Valuator(Valuator const &o); // cannot copy
void operator = (Valuator const &o);
void reset()
{ _d.v = 0; _d.size = 0; _d.offset = 0; }
public:
Valuator(Valuator &o) : _d(o._d)
{ o.reset(); }
void swap(Valuator &o)
{
if (&o == this)
return;
Data d = _d;
_d = o._d;
o._d = d;
}
void operator = (Valuator &o)
{
if (&o == this)
return;
if (_d.size)
delete [] _d.v;
_d = o._d;
o.reset();
}
Valuator() : _d() {}
void create(unsigned size, unsigned offset)
{
if (_d.size)
delete [] _d.v;
_d.size = size;
_d.offset = offset;
if (size)
_d.v = new V[size];
clear();
}
explicit Valuator(unsigned size, unsigned offset)
: _d(size, offset, size ? new V[size] : 0)
{ clear(); }
~Valuator() { if (_d.size) delete [] _d.v; }
void clear()
{
if (!_d.size)
return;
for (unsigned i = 0; i < _d.size; ++i)
_d.v[i] = 0;
}
bool valid(unsigned idx) const
{
if (idx < _d.offset)
return false;
idx -= _d.offset;
if (idx >= _d.size)
return false;
// the lsb is used for validity
return _d.v[idx] & 1;
}
Value<V> get(unsigned idx) const
{
if (idx < _d.offset)
return Value<V>();
idx -= _d.offset;
if (idx >= _d.size)
return Value<V>();
return Value<V>(true, _d.v[idx]);
}
Value<V> operator [] (unsigned idx) const
{ return get(idx); }
void set(unsigned idx, V v)
{
if (idx < _d.offset)
return;
idx -= _d.offset;
if (idx >= _d.size)
return;
_d.v[idx] = (v << 1) | 1;
}
void inv(unsigned idx)
{
if (idx < _d.offset)
return;
idx -= _d.offset;
if (idx >= _d.size)
return;
_d.v[idx] = 0;
}
unsigned size() const
{ return _d.size; }
unsigned offset() const
{ return _d.offset; }
private:
struct Data
{
Data() : size(0), offset(0), v(0) {}
Data(unsigned size, unsigned offset, V *v)
: size(size), offset(offset), v(v)
{}
unsigned size;
unsigned offset;
V *v;
} _d;
};
};

View File

@@ -0,0 +1,128 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/cxx/dlist>
#include <l4/mag-gfx/geometry>
#include <l4/mag-gfx/font>
#include <l4/mag-gfx/gfx_colors>
#include <l4/mag/server/mode>
#include <l4/mag/server/session>
#include <l4/re/event>
namespace Mag_gfx {
class Canvas;
}
namespace Mag_server {
using namespace Mag_gfx;
class View_stack;
class Session;
class Hid_report;
class View : public cxx::D_list_item, public Rect
{
private:
friend class View_stack;
View(View const &);
void operator = (View const &);
unsigned _flags;
Point _label_pos;
Area _label_sz;
protected:
explicit View(Rect const &size, unsigned flags = 0)
: Rect(size), _flags(flags)
{}
public:
enum Consts
{
Label_sep = 8 // space between session label and view title
};
static Rgb32::Color frame_color() { return Rgb32::Color(255, 200, 127); }
static Rgb32::Color kill_color() { return Rgb32::Color(255, 0, 0); }
enum
{
F_transparent = 0x01,
F_need_frame = 0x02,
F_ignore = 0x04,
F_focused = 0x08,
F_background = 0x10,
F_above = 0x20,
F_no_label = 0x40,
F_super_view = 0x80,
};
void set_geometry(Rect const &p)
{ this->Rect::operator = (p); }
Area size() const { return Area(w(), h()); }
bool transparent() const { return _flags & F_transparent; }
bool need_frame() const { return _flags & F_need_frame; }
bool ignore() const { return _flags & F_ignore; }
bool focused() const { return _flags & F_focused; }
bool background() const { return _flags & F_background; }
bool above() const { return _flags & F_above; }
bool super_view() const { return _flags & F_super_view; }
void set_as_background() { _flags |= F_background; }
void set_above(bool on)
{
if (on)
_flags |= F_above;
else
_flags &= ~F_above;
}
void set_focus(bool on)
{
if (on)
_flags |= F_focused;
else
_flags &= ~F_focused;
}
typedef L4Re::Event_buffer::Event Event;
virtual void draw(Canvas *, View_stack const *, Mode) const = 0;
virtual void handle_event(Hid_report *, Point const &, bool core_dev) = 0;
virtual ~View() {}
virtual Session *session() const { return 0; }
char const *title() const { return 0; }
Area calc_label_sz(Font const *font);
Point label_pos() const { return _label_pos; }
void label_pos(Point const &pos) { _label_pos = pos; }
Area label_sz() const { return _label_sz; }
int frame_width() const { return 4; }
};
inline
Area
View::calc_label_sz(Font const *font)
{
char const *const l1 = session()->label();
char const *const l2 = title();
_label_sz = Area(font->str_w(l1) + (l2 ? (Label_sep + font->str_w(l2) + 2) : 2), font->str_h(l1) + 2);
return _label_sz;
}
}

View File

@@ -0,0 +1,187 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/cxx/dlist>
#include <l4/re/video/view>
#include <l4/mag-gfx/canvas>
#include <l4/mag/server/view>
#include <l4/cxx/observer>
#include <cassert>
namespace Mag_server {
using namespace Mag_gfx;
class View_stack
{
private:
class Dummy_view : public View
{
public:
Dummy_view() : View(Rect(Point(0,0), Area(0,0)), F_ignore) {}
void draw(Canvas *, View_stack const *, Mode) const {}
void handle_event(Hid_report *, Point const &, bool) {}
};
typedef cxx::D_list<View> View_list;
typedef View_list::Iterator View_iter;
typedef View_list::Const_iterator Const_view_iter;
Dummy_view _no_stay_top_v;
Canvas *_canvas;
View *const _no_stay_top;
View_list _top;
View *const _background;
View *_focused;
Mode _mode;
L4Re::Video::View *_canvas_view;
Font const *_label_font;
cxx::Notifier _mode_notifier;
Rect outline(View const *v) const;
void draw_frame(View const *v) const;
void draw_label(View const *v) const;
void insert_before(View *o, View *p)
{ _top.insert_before(o, _top.iter(p)); }
void insert_after(View *o, View *p)
{ _top.insert_after(o, _top.iter(p)); }
public:
explicit View_stack(Canvas *canvas, L4Re::Video::View *canvas_view, View *bg,
Font const *label_font)
: _canvas(canvas), _no_stay_top(&_no_stay_top_v),
_background(bg), _canvas_view(canvas_view), _label_font(label_font)
{
_top.push_front(_no_stay_top);
_top.insert_after(bg, _top.iter(_no_stay_top));
}
View *top() const { return const_cast<View*>(*_top.begin()); }
virtual
void refresh_view(View const *v, View const *dst, Rect const &rect) const;
/**
* Draw whole view stack
*/
void update_all_views() const
{
Rect r(Point(), _canvas->size());
place_labels(r);
refresh_view(0, 0, r);
}
virtual void flush();
Canvas *canvas() const { return _canvas; }
Mode mode() const { return _mode; }
void toggle_mode(Mode::Mode_flag m, bool update = false)
{
_mode.toggle(m);
if (update)
update_all_views();
_mode_notifier.notify();
}
void set_mode(Mode::Mode_flag m, bool on, bool update = false)
{
_mode.set(m, on);
if (update)
update_all_views();
_mode_notifier.notify();
}
void set_focused(View *v);
View *focused() const { return _focused; }
virtual
void viewport(View *v, Rect const &pos, bool redraw) const;
void draw_recursive(View const *v, View const *dst, Rect const &,
View const *bg) const;
virtual
void draw_recursive(View const *v, View const *dst, Rect const &) const;
virtual
void stack(View *v, View *pivot, bool behind = true);
void push_top(View *v, bool stay_top = false)
{ stack(v, _no_stay_top, !stay_top); }
void push_bottom(View *v);
void remove(View *v)
{ if (_top.in_list(v)) _top.remove(v); }
void forget_view(View *v)
{
assert (v != _no_stay_top);
assert (v != _background);
remove(v);
refresh_view(0, 0, outline(v));
}
bool on_top(View const *v) const
{ return *++_top.iter(_no_stay_top) == v; }
View *next_view(View *c) const
{
View_iter i = _top.iter(c);
++i;
if (i != _top.end())
return *i;
else
return 0;
}
void add_mode_observer(cxx::Observer *o) { _mode_notifier.add(o); }
virtual
View *find(Point const &pos) const;
virtual ~View_stack() {}
private:
View *current_background() const
{
Session *current_session = focused() ? focused()->session() : 0;
return current_session ? current_session->background() : 0;
}
View const *next_view(View const*, View const *bg) const;
View *next_view(View *v, View const *bg) const
{ return const_cast<View*>(next_view(const_cast<View const *>(v), bg)); }
void optimize_label_rec(View *cv, View *lv, Rect const &rect, Rect *optimal,
View *bg) const;
void do_place_labels(Rect const &rect) const;
void place_labels(Rect const &rect) const
{
if (_mode.flat())
return;
do_place_labels(rect);
}
};
}

View File

@@ -0,0 +1,8 @@
PKGDIR ?= ..
L4DIR ?= $(PKGDIR)/../..
TARGET = src client_fb input_libinput input_event background mag_client \
session_manager
include $(L4DIR)/mk/subdir.mk
$(filter-out src,$(TARGET)): src

View File

@@ -0,0 +1,7 @@
PKGDIR ?= ../..
L4DIR ?= $(PKGDIR)/../..
PLUGIN := client_fb
SRC_CC := client_fb.cc service.cc
include $(PKGDIR)/plugins/plugin.mk

View File

@@ -0,0 +1,419 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "client_fb.h"
#include <l4/mag-gfx/clip_guard>
#include <l4/mag-gfx/texture>
#include <l4/mag/server/view_stack>
#include <l4/mag/server/factory>
#include <l4/re/env>
#include <l4/re/event_enums.h>
#include <l4/re/error_helper>
#include <l4/re/util/cap_alloc>
#include <l4/re/util/unique_cap>
#include <l4/sys/factory>
#include <l4/re/util/meta>
#include <l4/re/console>
#include <l4/re/event-sys.h>
#include <l4/mag/server/user_state>
#include <cstdio>
#include <cstring>
namespace Mag_server {
using L4Re::chksys;
using L4Re::chkcap;
enum { Bar_height = 16 };
Client_fb::Client_fb(Core_api const *core)
: View(Rect(), F_need_frame),
Icu_svr(1, &_ev_irq),
_core(core), _fb(0),
_bar_height(Bar_height),
_flags(0)
{}
void
Client_fb::set_geometry_prop(Session *_s, Property_handler const *, cxx::String const &v)
{
Client_fb *s = static_cast<Client_fb*>(_s);
// ignore multiple geometry properties
if (s->_fb)
return;
int w, h, x=50, y=50;
int r;
cxx::String a = v;
r = a.from_dec(&w);
if (r >= a.len() || a[r] != 'x')
L4Re::chksys(-L4_EINVAL, "invalid geometry format");
a = a.substr(r + 1);
r = a.from_dec(&h);
if (r < a.len() && a[r] == '+')
{
a = a.substr(r + 1);
r = a.from_dec(&x);
}
if (r < a.len() && a[r] == '+')
{
a = a.substr(r + 1);
r = a.from_dec(&y);
}
if (w <= 0 || h <= 0 || w >= 10000 || h >= 10000)
L4Re::chksys(-L4_ERANGE, "invalid geometry (too big)");
Area sz = s->_core->user_state()->vstack()->canvas()->size();
if (x < 10 - w)
x = 10 - w;
if (x >= sz.w())
x = sz.w() - 10;
if (y < 10 - h)
y = 10 - h;
if (y >= sz.h())
y = sz.h() - 10;
s->set_geometry(Rect(Point(x, y), Area(w, h)));
}
void
Client_fb::set_flags_prop(Session *_s, Property_handler const *p, cxx::String const &)
{
Client_fb *s = static_cast<Client_fb*>(_s);
if (!strcmp(p->tag, "focus"))
s->_flags |= F_fb_focus;
if (!strcmp(p->tag, "shaded"))
s->_flags |= F_fb_shaded;
if (!strcmp(p->tag, "fixed"))
s->_flags |= F_fb_fixed_location;
}
void
Client_fb::set_bar_height_prop(Session *_s, Property_handler const *, cxx::String const &v)
{
Client_fb *s = static_cast<Client_fb*>(_s);
int r = v.from_dec(&s->_bar_height);
if (r < v.len())
L4Re::chksys(-L4_EINVAL, "invalid bar height format");
s->_bar_height = std::max(std::min(s->_bar_height, 100), 4);
}
int
Client_fb::setup()
{
using L4Re::Video::View;
using L4Re::Video::Color_component;
using L4Re::Video::Goos;
Area res(size());
auto ds = L4Re::Util::make_unique_cap<L4Re::Dataspace>();
Screen_factory *sf = dynamic_cast<Screen_factory*>(_core->user_state()->vstack()->canvas()->type()->factory);
//Screen_factory *sf = dynamic_cast<Screen_factory*>(Rgb16::type()->factory);
L4Re::chksys(L4Re::Env::env()->mem_alloc()->alloc(sf->get_texture_size(res),
ds.get()));
L4Re::Rm::Unique_region<void *> dsa;
L4Re::chksys(L4Re::Env::env()->rm()
->attach(&dsa, ds->size(),
L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
L4::Ipc::make_cap_rw(ds.get()), 0,
L4_SUPERPAGESHIFT));
_fb = sf->create_texture(res, dsa.get());
set_geometry(Rect(p1(), visible_size()));
dsa.release();
_fb_ds = ds.release();
_view_info.flags = View::F_none;
_view_info.view_index = 0;
_view_info.xpos = 0;
_view_info.ypos = 0;
_view_info.width = _fb->size().w();
_view_info.height = _fb->size().h();
_view_info.buffer_offset = 0;
_view_info.buffer_index = 0;
_view_info.bytes_per_line = _view_info.width * _fb->type()->bytes_per_pixel();
_view_info.pixel_info = *_fb->type();
_screen_info.flags = Goos::F_pointer;
_screen_info.width = _view_info.width;
_screen_info.height = _view_info.height;
_screen_info.num_static_views = 1;
_screen_info.num_static_buffers = 1;
_screen_info.pixel_info = _view_info.pixel_info;
L4Re::Env const *e = L4Re::Env::env();
_ev_ds = L4Re::Util::make_unique_cap<L4Re::Dataspace>();
chksys(e->mem_alloc()->alloc(L4_PAGESIZE, _ev_ds.get()));
chksys(e->rm()->attach(&_ev_ds_m, L4_PAGESIZE,
L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
L4::Ipc::make_cap_rw(_ev_ds.get()), 0, L4_PAGESHIFT));
_events = L4Re::Event_buffer(_ev_ds_m.get(), L4_PAGESIZE);
calc_label_sz(_core->label_font());
return 0;
}
void
Client_fb::view_setup()
{
if (_flags & F_fb_focus)
_core->user_state()->set_focus(this);
}
void
Client_fb::draw(Canvas *canvas, View_stack const *, Mode mode) const
{
/* use dimming in x-ray mode */
Canvas::Mix_mode op = mode.flat() ? Canvas::Solid : Canvas::Mixed;
/* do not dim the focused view in x-ray mode */
if (mode.xray() && !mode.kill() && focused())
op = Canvas::Solid;
/*
* The view content and label should never overdraw the
* frame of the view in non-flat Nitpicker modes. The frame
* is located outside the view area. By shrinking the
* clipping area to the view area, we protect the frame.
*/
Clip_guard clip_guard(canvas, *this);
/*
* If the clipping area shrinked to zero,
* we do not process drawing operations.
*/
if (!canvas->clip_valid()/* || !_session*/)
return;
/* draw view content */
Rgb32::Color mix_color = /*mode.kill() ? kill_color() :*/ session()->color();
canvas->draw_box(top(_bar_height), Rgb32::Color(56, 68, 88));
canvas->draw_texture(_fb, mix_color, p1() + Point(0, _bar_height), op);
}
Area
Client_fb::visible_size() const
{
if (_flags & F_fb_shaded)
return Area(_fb->size().w(), _bar_height);
return _fb->size() + Area(0, _bar_height);
}
void
Client_fb::toggle_shaded()
{
Rect r = *this;
_flags ^= F_fb_shaded;
Rect n = Rect(p1(), visible_size());
set_geometry(n);
_core->user_state()->vstack()->refresh_view(0, 0, r | n);
}
bool
Client_fb::handle_core_event(Hid_report *e, Point const &mouse)
{
static Point left_drag;
static l4_umword_t drag_dev;
bool consumed = false;
Valuator<int> const *abs = e->get_vals(3);
if (abs && abs->get(1).valid() && left_drag != Point())
{
Rect npos = Rect(p1() + mouse - left_drag, size());
left_drag = mouse;
_core->user_state()->vstack()->viewport(this, npos, true);
consumed = true;
}
Rect bar = top(_bar_height);
Hid_report::Key_event const *btn_left = e->find_key_event(L4RE_BTN_LEFT);
View_stack *_stack = _core->user_state()->vstack();
if (btn_left && btn_left->value == 1 && !_stack->on_top(this))
_stack->push_top(this);
if (btn_left && bar.contains(mouse) && !(_flags & F_fb_fixed_location))
{
if (btn_left->value == 1 && left_drag == Point())
{
left_drag = mouse;
drag_dev = e->device_id();
}
else if (btn_left->value == 0 && e->device_id() == drag_dev)
left_drag = Point();
consumed = true;
}
Hid_report::Key_event const *btn_middle = e->find_key_event(L4RE_BTN_MIDDLE);
if (btn_middle && btn_middle->value == 1 && bar.contains(mouse))
{
toggle_shaded();
consumed = true;
}
// no events if window is shaded
if (consumed || (_flags & F_fb_shaded))
return true;
return false;
}
namespace {
struct Abs_xfrm
{
Point p1;
Area sz;
Axis_info_vector const *v;
Abs_xfrm(Axis_info_vector const *v, Point const &p1, Area const &sz)
: p1(p1), sz(sz), v(v) {}
void operator () (unsigned axis, int &val) const
{
Axis_info const *ai = v->get(axis);
if (ai)
{
switch (ai->mode)
{
case 1:
val = cxx::min(sz.w(), cxx::max(0, val - p1.x()));
break;
case 2:
val = cxx::min(sz.h(), cxx::max(0, val - p1.y()));
break;
default:
break;
}
}
}
};
}
void
Client_fb::handle_event(Hid_report *e, Point const &mouse, bool core_dev)
{
static Point left_drag;
if (core_dev && handle_core_event(e, mouse))
return;
// no events if window is shaded
if (_flags & F_fb_shaded)
return;
Abs_xfrm xfrm(e->abs_infos(), p1() + Point(0, _bar_height), _fb->size());
bool trigger = post_hid_report(e, _events, xfrm);
if (trigger)
_ev_irq.trigger();
}
void
Client_fb::put_event(l4_umword_t stream, int type, int code, int value,
l4_uint64_t time)
{
L4Re::Event_buffer::Event e;
e.time = time;
e.payload.stream_id = stream;
e.payload.type = type;
e.payload.code = code;
e.payload.value = value;
_events.put(e);
_ev_irq.trigger();
}
int
Client_fb::refresh(int x, int y, int w, int h)
{
_core->user_state()->vstack()->refresh_view(this, 0, Rect(p1() + Point(x, y + _bar_height), Area(w, h)));
return 0;
}
int
Client_fb::get_stream_info_for_id(l4_umword_t id, L4Re::Event_stream_info *info)
{
return _core->user_state()->get_input_stream_info_for_id(id, info);
}
int
Client_fb::get_abs_info(l4_umword_t id, unsigned naxes, unsigned const *axes,
L4Re::Event_absinfo *infos)
{
unsigned char ax_mode[naxes];
int i = _core->user_state()->get_input_axis_info(id, naxes, axes, infos, ax_mode);
// < 0: means we got an error
// == 0: means the device is an non-core device and not translated
// == 1: means ths device is used as core input pointer (adjust X and Y)
if (i < 0)
return i;
for (unsigned a = 0; a < naxes; ++a)
{
switch (ax_mode[a])
{
default: break;
case 0: break;
case 1:
infos[a].min = 0;
infos[a].max = _fb->size().w();
break;
case 2:
infos[a].min = 0;
infos[a].max = _fb->size().h();
break;
}
}
return i;
}
void
Client_fb::destroy()
{
_core->user_state()->forget_view(this);
delete _fb;
_fb = 0;
}
}

View File

@@ -0,0 +1,125 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag-gfx/canvas>
#include <l4/mag/server/view>
#include <l4/mag/server/session>
#include <l4/re/console>
#include <l4/re/util/video/goos_svr>
#include <l4/re/util/event_svr>
#include <l4/sys/cxx/ipc_epiface>
#include <l4/re/util/unique_cap>
#include <l4/re/rm>
#include <l4/re/util/icu_svr>
#include <l4/mag/server/plugin>
namespace Mag_server {
class Client_fb
: public View, public Session,
public L4::Epiface_t<Client_fb, L4Re::Console, Object>,
public L4Re::Util::Video::Goos_svr,
public L4Re::Util::Icu_cap_array_svr<Client_fb>
{
private:
typedef L4Re::Util::Icu_cap_array_svr<Client_fb> Icu_svr;
Core_api const *_core;
Texture *_fb;
int _bar_height;
L4Re::Util::Unique_cap<L4Re::Dataspace> _ev_ds;
L4Re::Rm::Unique_region<void*> _ev_ds_m;
L4Re::Event_buffer _events;
Irq _ev_irq;
enum
{
F_fb_fixed_location = 1 << 0,
F_fb_shaded = 1 << 1,
F_fb_focus = 1 << 2,
};
unsigned _flags;
public:
int setup();
void view_setup();
explicit Client_fb(Core_api const *core);
void toggle_shaded();
void draw(Canvas *, View_stack const *, Mode) const;
void handle_event(Hid_report *e, Point const &mouse, bool core_dev);
bool handle_core_event(Hid_report *e, Point const &mouse);
int get_stream_info_for_id(l4_umword_t id, L4Re::Event_stream_info *info);
int get_abs_info(l4_umword_t id, unsigned naxes, unsigned const *axes,
L4Re::Event_absinfo *infos);
using L4Re::Util::Video::Goos_svr::op_info;
using Icu_svr::op_info;
int refresh(int x, int y, int w, int h);
Area visible_size() const;
void destroy();
Session *session() const { return const_cast<Client_fb*>(this); }
static void set_geometry_prop(Session *s, Property_handler const *p, cxx::String const &v);
static void set_flags_prop(Session *s, Property_handler const *p, cxx::String const &v);
static void set_bar_height_prop(Session *s, Property_handler const *p, cxx::String const &v);
void put_event(l4_umword_t stream, int type, int code, int value,
l4_uint64_t time);
long op_get_buffer(L4Re::Event::Rights, L4::Ipc::Cap<L4Re::Dataspace> &ds)
{
_events.reset();
ds = L4::Ipc::Cap<L4Re::Dataspace>(_ev_ds.get(), L4_CAP_FPAGE_RW);
return L4_EOK;
}
long op_get_num_streams(L4Re::Event::Rights)
{ return -L4_ENOSYS; }
long op_get_stream_info(L4Re::Event::Rights, int, L4Re::Event_stream_info &)
{ return -L4_ENOSYS; }
long op_get_stream_info_for_id(L4Re::Event::Rights, l4_umword_t id,
L4Re::Event_stream_info &info)
{ return get_stream_info_for_id(id, &info); }
long op_get_axis_info(L4Re::Event::Rights, l4_umword_t id,
L4::Ipc::Array_in_buf<unsigned, unsigned long> const &axes,
L4::Ipc::Array_ref<L4Re::Event_absinfo, unsigned long> &info)
{
unsigned naxes = cxx::min<unsigned>(L4RE_ABS_MAX, axes.length);
info.length = 0;
L4Re::Event_absinfo _info[naxes];
int r = get_abs_info(id, naxes, axes.data, _info);
if (r < 0)
return r;
for (unsigned i = 0; i < naxes; ++i)
info.data[i] = _info[i];
info.length = naxes;
return r;
}
long op_get_stream_state_for_id(L4Re::Event::Rights, l4_umword_t,
L4Re::Event_stream_state &)
{ return -L4_ENOSYS; }
};
}

View File

@@ -0,0 +1,90 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/re/util/object_registry>
#include <l4/re/env>
#include <l4/re/console>
#include <l4/re/util/cap_alloc>
#include <l4/re/error_helper>
#include <l4/re/rm>
#include <l4/re/dataspace>
#include <l4/re/util/meta>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include "client_fb.h"
#include <l4/mag-gfx/canvas>
#include <l4/mag/server/user_state>
#include <l4/mag/server/factory>
#include "service.h"
#include <l4/sys/kdebug.h>
namespace Mag_server {
void Service::start(Core_api *core)
{
_core = core;
if (!reg()->register_obj(cxx::Ref_ptr<Service>(this), "svc").is_valid())
printf("Service registration failed.\n");
else
printf("Plugin: Frame-buffer service started\n");
}
namespace {
Session::Property_handler const _client_fb_opts[] =
{ { "g", true, &Client_fb::set_geometry_prop },
{ "geometry", true, &Client_fb::set_geometry_prop },
{ "focus", false, &Client_fb::set_flags_prop },
{ "shaded", false, &Client_fb::set_flags_prop },
{ "fixed", false, &Client_fb::set_flags_prop },
{ "barheight", true, &Client_fb::set_bar_height_prop },
{ 0, 0, 0 }
};
};
long
Service::op_create(L4::Factory::Rights, L4::Ipc::Cap<void> &obj,
l4_mword_t proto, L4::Ipc::Varg_list<> const &args)
{
if (!L4::kobject_typeid<L4Re::Console>()->has_proto(proto))
return -L4_ENODEV;
cxx::Ref_ptr<Client_fb> x(new Client_fb(_core));
_core->set_session_options(x.get(), args, _client_fb_opts);
x->setup();
_core->register_session(x.get());
ust()->vstack()->push_top(x.get());
x->view_setup();
reg()->register_obj(x);
x->obj_cap()->dec_refcnt(1);
obj = L4::Ipc::make_cap(x->obj_cap(), L4_CAP_FPAGE_RWSD);
return 0;
}
void
Service::destroy()
{
printf("MAG: destroying the fb_client_service, holla\n");
}
Service::~Service()
{
printf("MAG: destroy FB svc\n");
}
static Service _fb_service("frame-buffer");
}

View File

@@ -0,0 +1,45 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/re/video/goos>
#include <l4/mag/server/plugin>
#include <l4/mag/server/user_state>
#include <l4/sys/cxx/ipc_epiface>
namespace Mag_server {
class Service :
public L4::Epiface_t<Service, L4::Factory, Object>,
private Plugin
{
private:
Core_api const *_core;
protected:
User_state *ust() const { return _core->user_state(); }
Registry *reg() const { return _core->registry(); }
public:
Service(char const *name) : Plugin(name) {}
char const *type() const { return "service"; }
void start(Core_api *core);
//Canvas *screen() const { return _ust.vstack()->canvas(); }
void destroy();
~Service();
long op_create(L4::Factory::Rights, L4::Ipc::Cap<void> &obj,
l4_mword_t proto, L4::Ipc::Varg_list<> const &args);
};
}

View File

@@ -0,0 +1,6 @@
PKGDIR ?= ../..
L4DIR ?= $(PKGDIR)/../..
PLUGIN := input-event
SRC_CC := input_event.cc
include $(PKGDIR)/plugins/plugin.mk

View File

@@ -0,0 +1,77 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag/server/input_driver>
#include <l4/mag/server/input_source>
#include <l4/sys/capability>
#include <l4/re/console>
#include <l4/re/util/event>
namespace Mag_server {
class Input_source_event : public Input_source
{
public:
L4::Cap<L4Re::Event> _ev_cap;
L4Re::Util::Event _event;
void core(Core_api *c) { _core = c; }
void poll_events()
{
while (L4Re::Event_buffer::Event *e = _event.buffer().next())
{
post_event(e);
e->free();
}
}
int get_stream_info(l4_umword_t stream_id, L4Re::Event_stream_info *info)
{ return _ev_cap->get_stream_info_for_id(stream_id, info); }
int get_axis_info(l4_umword_t stream_id, unsigned naxes, unsigned *axes,
L4Re::Event_absinfo *info)
{ return _ev_cap->get_axis_info(stream_id, naxes, axes, info); }
};
class Input_driver_event : public Input_driver
{
private:
Input_source_event _source_be, _source_ev;
public:
Input_driver_event() : Input_driver("L4Re::Event") {}
void start(Core_api *core)
{
L4::Cap<L4Re::Event> c =
L4::cap_dynamic_cast<L4Re::Event>(core->backend_fb());
_source_be.core(core);
_source_ev.core(core);
if (c && !_source_be._event.init_poll(c))
{
_source_be._ev_cap = c;
core->add_input_source(&_source_be);
}
c = L4Re::Env::env()->get_cap<L4Re::Event>("ev");
if (c && !_source_ev._event.init_poll(c))
{
_source_ev._ev_cap = c;
core->add_input_source(&_source_ev);
}
}
};
static Input_driver_event _evinput;
}

View File

@@ -0,0 +1,8 @@
PKGDIR ?= ../..
L4DIR ?= $(PKGDIR)/../..
PLUGIN := input-libinput
PLUGIN_STATIC_ONLY := y
SRC_CC := input_libinput.cc
REQUIRES_LIBS += input
include $(PKGDIR)/plugins/plugin.mk

View File

@@ -0,0 +1,54 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag/server/input_driver>
#include <l4/mag/server/input_source>
#include <l4/input/libinput.h>
namespace {
using Mag_server::Input_driver;
using Mag_server::Input_source;
using Mag_server::Core_api;
using Mag_server::User_state;
class Input_driver_libinput : public Input_driver, public Input_source
{
public:
Input_driver_libinput() : Input_driver("libinput") {}
void start(Core_api *core)
{
if (l4input_init(0xff, 0) == 0)
{
_core = core;
core->add_input_source(this);
}
}
void poll_events()
{
enum { N=20 };
L4Re::Event_buffer::Event _evb[N];
while (l4input_ispending())
{
L4Re::Event_buffer::Event *e = _evb;
for (int max = l4input_flush(_evb, N); max; --max, ++e)
post_event(e);
}
}
int get_stream_info(l4_umword_t stream_id, L4Re::Event_stream_info *info)
{ return l4evdev_stream_info_for_id(stream_id, info); }
int get_axis_info(l4_umword_t stream_id, unsigned naxes, unsigned *axes,
L4Re::Event_absinfo *info)
{ return l4evdev_absinfo(stream_id, naxes, axes, info); }
};
static Input_driver_libinput _libinput;
}

View File

@@ -0,0 +1,8 @@
PKGDIR ?= ../..
L4DIR ?= $(PKGDIR)/../..
PLUGIN := mag_client
SRC_CC := mag_client.cc
include $(PKGDIR)/plugins/plugin.mk

View File

@@ -0,0 +1,670 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/re/env>
#include <l4/re/namespace>
#include <l4/re/event_enums.h>
#include <l4/re/event-sys.h>
#include <l4/re/error_helper>
#include <l4/re/rm>
#include <l4/re/dataspace>
#include <l4/re/util/video/goos_svr>
#include <l4/re/util/event_svr>
#include <l4/re/util/icu_svr>
#include <l4/re/util/unique_cap>
#include <l4/re/video/goos-sys.h>
#include <l4/re/video/goos>
#include <l4/re/console>
#include <l4/re/util/meta>
#include <l4/mag/server/plugin>
#include <l4/mag/server/object>
#include <l4/mag/server/session>
#include <l4/mag/server/user_state>
#include <l4/mag-gfx/clip_guard>
#include <l4/mag-gfx/texture>
#include <l4/mag-gfx/factory>
#include <l4/cxx/list>
#include <l4/cxx/unique_ptr>
#include <cstring>
#include <cstdio>
#include <memory>
#include <vector>
#include <list>
namespace Mag_server { namespace {
using L4Re::Util::Unique_cap;
using std::auto_ptr;
using Mag_gfx::Texture;
using Mag_gfx::Area;
using L4Re::chksys;
class Mag_client :
public L4::Epiface_t<Mag_client, L4::Factory, Object>,
private Plugin
{
private:
Core_api const *_core;
public:
Mag_client() : Plugin("Mag client") {}
char const *type() const { return "Mag client"; }
void start(Core_api *core);
void destroy();
long op_create(L4::Factory::Rights rights, L4::Ipc::Cap<void> &obj,
l4_mword_t proto, L4::Ipc::Varg_list<> const &args);
};
class Client_buffer;
class Client_view;
class Mag_goos
: public Session,
public L4::Epiface_t<Mag_goos, L4Re::Console, Object>,
public L4Re::Util::Icu_cap_array_svr<Mag_goos>
{
private:
typedef L4Re::Util::Icu_cap_array_svr<Mag_goos> Icu_svr;
typedef L4Re::Video::Goos::Rights Goos_rights;
Core_api const *_core;
L4Re::Util::Unique_cap<L4Re::Dataspace> _ev_ds;
Irq _ev_irq;
L4Re::Rm::Unique_region<void*> _ev_ds_m;
L4Re::Event_buffer _events;
typedef std::vector<cxx::Ref_ptr<Client_buffer> > Buffer_vector;
typedef std::vector<cxx::unique_ptr<Client_view> > View_vector;
Buffer_vector _buffers;
View_vector _views;
public:
long op_info(Goos_rights, L4Re::Video::Goos::Info &i);
long op_get_static_buffer(Goos_rights, unsigned idx,
L4::Ipc::Cap<L4Re::Dataspace> &ds);
long op_create_buffer(Goos_rights, unsigned long, L4::Ipc::Cap<L4Re::Dataspace> &);
long op_delete_buffer(Goos_rights, unsigned)
{ return -L4_ENOSYS; }
long op_create_view(Goos_rights);
long op_delete_view(Goos_rights, unsigned);
long op_view_info(Goos_rights, unsigned idx, L4Re::Video::View::Info &info);
long op_set_view_info(Goos_rights, unsigned, L4Re::Video::View::Info const &);
long op_view_stack(Goos_rights, unsigned view, unsigned pivot, bool behind);
long op_view_refresh(Goos_rights, unsigned idx, int x, int y, int w, int h);
long op_refresh(Goos_rights, int x, int y, int w, int h);
long op_get_buffer(L4Re::Event::Rights, L4::Ipc::Cap<L4Re::Dataspace> &ds)
{
_events.reset();
ds = L4::Ipc::Cap<L4Re::Dataspace>(_ev_ds.get(), L4_CAP_FPAGE_RW);
return L4_EOK;
}
long op_get_num_streams(L4Re::Event::Rights)
{ return -L4_ENOSYS; }
long op_get_stream_info(L4Re::Event::Rights, int, L4Re::Event_stream_info &)
{ return -L4_ENOSYS; }
long op_get_stream_info_for_id(L4Re::Event::Rights, l4_umword_t id,
L4Re::Event_stream_info &info)
{ return _core->user_state()->get_input_stream_info_for_id(id, &info); }
long op_get_axis_info(L4Re::Event::Rights, l4_umword_t id,
L4::Ipc::Array_in_buf<unsigned, unsigned long> const &axes,
L4::Ipc::Array_ref<L4Re::Event_absinfo, unsigned long> &info)
{
unsigned naxes = cxx::min<unsigned>(L4RE_ABS_MAX, axes.length);
info.length = 0;
L4Re::Event_absinfo _info[naxes];
int r = _core->user_state()->get_input_axis_info(id, naxes, axes.data, _info, 0);
if (r < 0)
return r;
for (unsigned i = 0; i < naxes; ++i)
info.data[i] = _info[i];
info.length = naxes;
return r;
}
long op_get_stream_state_for_id(L4Re::Event::Rights, l4_umword_t,
L4Re::Event_stream_state &)
{ return -L4_ENOSYS; }
public:
Mag_goos(Core_api const *core);
using Icu_svr::op_info;
void put_event(Hid_report *e, bool trigger);
void put_event(l4_umword_t stream, int type, int code, int value,
l4_uint64_t time);
void destroy();
static void set_default_background(Session *_s, Property_handler const *, cxx::String const &);
};
class Client_buffer : public cxx::Ref_obj
{
private:
L4Re::Util::Unique_cap<L4Re::Dataspace> _ds;
L4Re::Rm::Unique_region<void *> _texture_mem;
unsigned long _size;
public:
unsigned index;
Client_buffer(Core_api const *core, unsigned long size);
L4::Cap<L4Re::Dataspace> ds_cap() const { return _ds.get(); }
void *local_addr() const { return _texture_mem.get(); }
unsigned long size() const { return _size; }
};
class Client_view : public View
{
private:
Core_api const *_core;
cxx::Ref_ptr<Client_buffer> _buffer;
Mag_goos *_screen;
Texture *_front_txt;
Texture *_back_txt;
unsigned long _buf_offset;
void swap_textures()
{
Texture *tmp = _front_txt;
asm volatile ("" : : : "memory");
_front_txt = _back_txt;
_back_txt = tmp;
}
public:
Client_view(Core_api const *core, Mag_goos *screen);
virtual ~Client_view();
void draw(Canvas *, View_stack const *, Mode) const;
void handle_event(Hid_report *e, Point const &mouse, bool core_dev);
void get_info(L4Re::Video::View::Info *inf) const;
void set_info(L4Re::Video::View::Info const &inf,
cxx::Ref_ptr<Client_buffer> const &b);
Session *session() const { return _screen; }
};
Client_view::Client_view(Core_api const *core, Mag_goos *screen)
: View(Rect(), F_need_frame), _core(core), _buffer(0), _screen(screen),
_buf_offset(0)
{
Pixel_info const *pi = core->user_state()->vstack()->canvas()->type();
_front_txt = pi->factory->create_texture(Area(0,0), (void*)1);
_back_txt = pi->factory->create_texture(Area(0,0), (void*)1);
calc_label_sz(core->label_font());
}
Client_view::~Client_view()
{
if (_screen && _screen->background() == this)
{
// look for other background views below
View_stack *vs = _core->user_state()->vstack();
// We can either search below this view in the stack, or
// we can search from the top of the stack to find the uppermost
// view of our session that is tagged as background
View *v = vs->next_view(this); // search below this view
// View *v = vs->top(); // Search from the top of the stack
for (; v; v = vs->next_view(v))
if (v != this && v->session() == _screen && v->background())
break;
_screen->background(v);
}
_core->user_state()->forget_view(this);
delete _back_txt;
delete _front_txt;
}
inline
void
Client_view::get_info(L4Re::Video::View::Info *inf) const
{
using L4Re::Video::Color_component;
inf->flags = L4Re::Video::View::F_fully_dynamic;
// we do not support changing the pixel format
inf->flags &= ~L4Re::Video::View::F_set_pixel;
if (above())
inf->flags |= L4Re::Video::View::F_above;
inf->xpos = x1();
inf->ypos = y1();
inf->width = w();
inf->height = h();
inf->buffer_offset = _buf_offset;
Pixel_info const *pi = 0;
pi = _front_txt->type();
inf->bytes_per_line = pi->bytes_per_pixel() * _front_txt->size().w();
inf->pixel_info = *pi;
if (_buffer)
inf->buffer_index = _buffer->index;
else
inf->buffer_index = ~0;
}
inline
void
Client_view::set_info(L4Re::Video::View::Info const &inf,
cxx::Ref_ptr<Client_buffer> const &b)
{
Pixel_info const *pi = _core->user_state()->vstack()->canvas()->type();
bool recalc_height = false;
_back_txt->size(_front_txt->size());
_back_txt->pixels(_front_txt->pixels());
if (inf.flags & L4Re::Video::View::F_set_flags)
set_above(inf.flags & L4Re::Video::View::F_above);
if (inf.flags & L4Re::Video::View::F_set_background)
{
_core->user_state()->vstack()->push_bottom(this);
set_as_background();
_screen->background(this);
}
if (inf.has_set_bytes_per_line())
{
_back_txt->size(Area(inf.bytes_per_line / pi->bytes_per_pixel(), 0));
recalc_height = true;
}
if (inf.has_set_buffer())
{
_back_txt->pixels((char *)b->local_addr() + _buf_offset);
_buffer = b;
recalc_height = true;
}
if (!_buffer)
{
_back_txt->size(Area(0, 0));
_back_txt->pixels((char *)0);
_front_txt->size(Area(0, 0));
_front_txt->pixels((char *)0);
}
if (inf.has_set_buffer_offset() && _buffer)
{
_back_txt->pixels((char *)_buffer->local_addr() + inf.buffer_offset);
_buf_offset = inf.buffer_offset;
recalc_height = true;
}
if (recalc_height && _buffer)
{
unsigned long w = _back_txt->size().w();
unsigned long bw = w * pi->bytes_per_pixel();
unsigned long h;
if (bw > 0 && w > 0)
{
h = _buffer->size();
if (h > _buf_offset)
h -= _buf_offset;
else
h = 0;
h /= bw;
}
else
{
w = 0;
h = 0;
}
_back_txt->size(Area(w, h));
}
if (_back_txt->size() != _front_txt->size()
|| _back_txt->pixels() != _front_txt->pixels())
swap_textures();
if (inf.has_set_position())
_core->user_state()->vstack()->viewport(this, Rect(Point(inf.xpos,
inf.ypos), Area(inf.width, inf.height)), true);
}
Mag_goos::Mag_goos(Core_api const *core)
: Icu_svr(1, &_ev_irq), _core(core)
{
L4Re::Env const *e = L4Re::Env::env();
_ev_ds = L4Re::Util::make_unique_cap<L4Re::Dataspace>();
chksys(e->mem_alloc()->alloc(L4_PAGESIZE, _ev_ds.get()));
chksys(e->rm()->attach(&_ev_ds_m, L4_PAGESIZE,
L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
L4::Ipc::make_cap_rw(_ev_ds.get())));
_events = L4Re::Event_buffer(_ev_ds_m.get(), L4_PAGESIZE);
}
void Mag_client::start(Core_api *core)
{
_core = core;
core->registry()->register_obj(cxx::Ref_ptr<Mag_client>(this), "mag");
if (!obj_cap().is_valid())
printf("Service registration failed.\n");
else
printf("Plugin: Mag_client service started\n");
}
void Mag_goos::set_default_background(Session *_s, Property_handler const *, cxx::String const &)
{
Mag_goos *s = static_cast<Mag_goos *>(_s);
s->flags(F_default_background, 0);
}
namespace {
Session::Property_handler const _opts[] =
{ { "default-background", false, &Mag_goos::set_default_background },
{ "dfl-bg", false, &Mag_goos::set_default_background },
{ 0, 0, 0 }
};
};
long
Mag_client::op_create(L4::Factory::Rights, L4::Ipc::Cap<void> &obj,
l4_mword_t proto, L4::Ipc::Varg_list<> const &args)
{
if (!L4::kobject_typeid<L4Re::Console>()->has_proto(proto))
return -L4_ENODEV;
cxx::Ref_ptr<Mag_goos> cf(new Mag_goos(_core));
_core->set_session_options(cf.get(), args, _opts);
_core->register_session(cf.get());
_core->registry()->register_obj(cf);
cf->obj_cap()->dec_refcnt(1);
obj = L4::Ipc::make_cap(cf->obj_cap(), L4_CAP_FPAGE_RWSD);
return L4_EOK;
}
void
Mag_client::destroy()
{
}
inline long
Mag_goos::op_info(Goos_rights, L4Re::Video::Goos::Info &i)
{
using L4Re::Video::Color_component;
using L4Re::Video::Goos;
Area a = _core->user_state()->vstack()->canvas()->size();
Pixel_info const *mag_pi = _core->user_state()->vstack()->canvas()->type();
i.width = a.w();
i.height = a.h();
i.flags = Goos::F_pointer
| Goos::F_dynamic_views
| Goos::F_dynamic_buffers;
i.num_static_views = 0;
i.num_static_buffers = 0;
i.pixel_info = *mag_pi;
return L4_EOK;
}
inline long
Mag_goos::op_create_buffer(Goos_rights, unsigned long size,
L4::Ipc::Cap<L4Re::Dataspace> &ds)
{
cxx::Ref_ptr<Client_buffer> b(new Client_buffer(_core, size));
_buffers.emplace_back(b);
b->index = _buffers.size() - 1;
ds = L4::Ipc::Cap<L4Re::Dataspace>(b->ds_cap(), L4_CAP_FPAGE_RW);
return b->index;
}
inline long
Mag_goos::op_create_view(Goos_rights)
{
cxx::unique_ptr<Client_view> v = cxx::make_unique<Client_view>(_core, this);
unsigned idx = 0;
for (View_vector::iterator i = _views.begin(); i != _views.end();
++i, ++idx)
if (!*i)
{
*i = cxx::move(v);
return idx;
}
_views.emplace_back(cxx::move(v));
return _views.size() - 1;
}
inline long
Mag_goos::op_delete_view(Goos_rights, unsigned idx)
{
if (idx >= _views.size())
return -L4_ERANGE;
_views[idx].reset(0);
return L4_EOK;
}
inline long
Mag_goos::op_get_static_buffer(Goos_rights, unsigned idx,
L4::Ipc::Cap<L4Re::Dataspace> &ds)
{
if (idx >= _buffers.size())
return -L4_ERANGE;
ds = L4::Ipc::Cap<L4Re::Dataspace>(_buffers[idx]->ds_cap(), L4_CAP_FPAGE_RW);
return L4_EOK;
}
inline long
Mag_goos::op_view_info(Goos_rights, unsigned idx, L4Re::Video::View::Info &info)
{
if (idx >= _views.size())
return -L4_ERANGE;
Client_view *cv = _views[idx].get();
L4Re::Video::View::Info vi;
vi.view_index = idx;
cv->get_info(&info);
return L4_EOK;
}
inline long
Mag_goos::op_set_view_info(Goos_rights, unsigned idx,
L4Re::Video::View::Info const &vi)
{
if (idx >= _views.size())
return -L4_ERANGE;
Client_view *cv = _views[idx].get();
cxx::Weak_ptr<Client_buffer> cb(nullptr);
if (vi.has_set_buffer())
{
if (vi.buffer_index >= _buffers.size())
return -L4_ERANGE;
cb = _buffers[vi.buffer_index];
}
cv->set_info(vi, cb);
return L4_EOK;
}
inline long
Mag_goos::op_view_stack(Goos_rights, unsigned cvi, unsigned pvi, bool behind)
{
Client_view *pivot = 0;
Client_view *cv;
if (cvi >= _views.size())
return -L4_ERANGE;
cv = _views[cvi].get();
if (pvi < _views.size())
pivot = _views[pvi].get();
if (!pivot)
{
if (!behind)
_core->user_state()->vstack()->push_bottom(cv);
else
_core->user_state()->vstack()->push_top(cv);
}
else
_core->user_state()->vstack()->stack(cv, pivot, behind);
return L4_EOK;
}
inline long
Mag_goos::op_view_refresh(Goos_rights, unsigned idx, int x, int y, int w, int h)
{
if (idx >= _views.size())
return -L4_ERANGE;
Client_view *cv = _views[idx].get();
_core->user_state()->vstack()->refresh_view(cv, 0, Rect(cv->p1() + Point(x,y), Area(w,h)));
return L4_EOK;
}
inline long
Mag_goos::op_refresh(Goos_rights, int x, int y, int w, int h)
{
_core->user_state()->vstack()->refresh_view(0, 0, Rect(Point(x,y), Area(w,h)));
return L4_EOK;
}
void
Mag_goos::destroy()
{
_buffers.clear();
_views.clear();
}
Client_buffer::Client_buffer(Core_api const *, unsigned long size)
: _size(l4_round_page(size))
{
L4Re::Rm::Unique_region<void *> dsa;
_ds = L4Re::Util::make_unique_cap<L4Re::Dataspace>();
L4Re::chksys(L4Re::Env::env()->mem_alloc()->alloc(_size, _ds.get()));
L4Re::chksys(L4Re::Env::env()->rm()
->attach(&dsa, _size,
L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
L4::Ipc::make_cap_rw(_ds.get())));
_texture_mem = cxx::move(dsa);
}
void
Mag_goos::put_event(Hid_report *e, bool _trigger)
{
if (post_hid_report(e, _events, Axis_xfrm_noop()) && _trigger)
_ev_irq.trigger();
}
void
Mag_goos::put_event(l4_umword_t stream, int type, int code, int value,
l4_uint64_t time)
{
L4Re::Event_buffer::Event e;
e.time = time;
e.payload.stream_id = stream;
e.payload.type = type;
e.payload.code = code;
e.payload.value = value;
_events.put(e);
_ev_irq.trigger();
}
void
Client_view::draw(Canvas *c, View_stack const *, Mode mode) const
{
Canvas::Mix_mode op = mode.flat() ? Canvas::Solid : Canvas::Mixed;
if (mode.xray() && !mode.kill() && focused())
op = Canvas::Solid;
Clip_guard cg(c, *this);
if (!c->clip_valid())
return;
Rgb32::Color mix_color = /*mode.kill() ? kill_color() :*/ session()->color();
Area s(0, 0);
if (_buffer)
{
c->draw_texture(_front_txt, mix_color, p1(), op);
s = _front_txt->size();
}
Area r = size() - s;
if (r.h() > 0)
c->draw_box(Rect(p1() + Point(0, s.h()), Area(size().w(), r.h())), mix_color);
if (r.w() > 0 && size().h() != r.h())
c->draw_box(Rect(p1() + Point(s.w(), 0), Area(r.w(), s.h())), mix_color);
}
void
Client_view::handle_event(Hid_report *e, Point const &, bool)
{
_screen->put_event(e, true);
}
static Mag_client _mag_client;
}}

View File

@@ -0,0 +1,15 @@
# generic plugin stuff
TARGET := libmag-$(PLUGIN).a
ifneq ($(PLUGIN_STATIC_ONLY),y)
TARGET += libmag-$(PLUGIN).so
endif
LDFLAGS += --unique
LINK_INCR := libmag-$(PLUGIN).a
LDFLAGS_libmag-$(PLUGIN).so += -lmag-plugin.o
PC_FILENAME := mag-$(PLUGIN)
REQUIRES_LIBS += libstdc++
include $(L4DIR)/mk/lib.mk
$(GENERAL_D_LOC): $(PKGDIR)/plugins/plugin.mk

View File

@@ -0,0 +1,8 @@
PKGDIR ?= ../..
L4DIR ?= $(PKGDIR)/../..
PLUGIN := session_manager
SRC_CC := session_manager.cc
include $(PKGDIR)/plugins/plugin.mk

View File

@@ -0,0 +1,154 @@
/*
* (c) 2011 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag/server/session>
#include <l4/mag/server/plugin>
#include <l4/mag/server/view>
#include <l4/mag/server/user_state>
#include <l4/mag/server/menu>
#include <l4/mag-gfx/canvas>
#include <l4/mag-gfx/clip_guard>
#include <l4/re/event_enums.h>
namespace Mag_server { namespace {
typedef Menu<Session_list> Session_menu;
class Session_manager_view : public View, private cxx::Observer
{
private:
Core_api const *_core;
Session_menu _m;
bool _visible;
struct So : public Observer
{
explicit So(Session_manager_view *v) : v(v) {}
Session_manager_view *v;
void notify() { v->sessions_changed(); }
};
So _session_observer;
public:
explicit Session_manager_view(Core_api const *core)
: View(Rect(), View::F_super_view /*| F_transparent*/), _core(core),
_m(core, this, core->sessions()),
_visible(false), _session_observer(this)
{ }
Observer *mode_observer() { return this; }
Observer *session_observer() { return &_session_observer; }
void handle_event(Hid_report *e, Point const &mouse, bool core_dev);
void draw(Canvas *canvas, View_stack const *, Mode mode) const;
void notify();
void sessions_changed();
void calc_geometry();
};
class Session_manager : public Plugin
{
private:
Session_manager_view *_v;
public:
Session_manager() : Plugin("Session manager") {}
char const *type() const { return "Session manager"; }
void start(Core_api *core);
void stop();
};
void
Session_manager::start(Core_api *core)
{
_v = new Session_manager_view(core);
core->user_state()->vstack()->add_mode_observer(_v->mode_observer());
core->add_session_observer(_v->session_observer());
}
void
Session_manager::stop()
{
if (_v)
delete _v;
_v = 0;
}
static Session_manager session_manager;
void
Session_manager_view::handle_event(Hid_report *e, Point const &mouse, bool)
{
Session_list::Const_iterator s = _m.handle_event(e, mouse - p1());
if (s != _core->sessions()->end())
{
s->ignore(!s->ignore());
_core->user_state()->vstack()->update_all_views();
}
}
void
Session_manager_view::draw(Canvas *canvas, View_stack const *, Mode) const
{
_m.draw(canvas, p1());
}
void
Session_manager_view::calc_geometry()
{
enum {
BORDER = 10,
};
Area cs = _core->user_state()->vstack()->canvas()->size();
cs = cs - Area(BORDER * 2, BORDER * 2);
Area sz =_m.calc_geometry(cs);
Point p = Point(20, 20).min(Point(BORDER, BORDER) + Point(cs) - Point(sz));
set_geometry(Rect(p, sz));
}
void
Session_manager_view::sessions_changed()
{
if (!_visible)
return;
calc_geometry();
_core->user_state()->vstack()->refresh_view(this, 0, *this);
}
void
Session_manager_view::notify()
{
View_stack *vs = _core->user_state()->vstack();
Mode m = vs->mode();
if (_visible && !m.kill())
{
_visible = false;
vs->remove(this);
vs->refresh_view(0, 0, *this);
}
else if (!_visible && m.kill())
{
_visible = true;
calc_geometry();
vs->push_top(this, true);
}
}
}}

View File

@@ -0,0 +1,12 @@
PKGDIR ?= ../..
L4DIR ?= $(PKGDIR)/../..
TARGET := libmag-plugin.o.a
SRC_CC := plugin.cc
LDFLAGS += --unique
include $(L4DIR)/mk/lib.mk
# On PIE builds, static libraries will be compiled with -fPIE. Override here
# with NOPICFLAGS because CPPFLAGS will go before and won't take effect.
NOPICFLAGS += -fPIC

View File

@@ -0,0 +1,43 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag/server/plugin>
#include <cstdio>
namespace Mag_server {
Plugin *Plugin::_first __attribute__((visibility("hidden")));
class Plugin_manager
{
public:
static void init(Core_api *core)
{
printf("core-init\n");
for (Plugin *p = Plugin::_first; p; p = p->_next)
{
printf("plugin: %p\n", p);
if (!p->started())
{
printf("starting %s plugin: %s\n", p->type(), p->name());
p->start(core);
}
}
}
};
extern "C" void init_plugin(Core_api *core);
void init_plugin(Core_api *core)
{
Plugin_manager::init(core);
}
}

View File

@@ -0,0 +1,7 @@
PKGDIR ?= ..
L4DIR ?= $(PKGDIR)/../..
TARGET = src
include $(L4DIR)/mk/subdir.mk
#l4: common

View File

@@ -0,0 +1,55 @@
PKGDIR ?= ../..
L4DIR ?= $(PKGDIR)/../..
TARGET = mag
PRIVATE_INCDIR = $(SRC_DIR)/../../include/server
SRC_CC := big_mouse.cc main.cc screen.cc view_stack.cc \
user_state.cc plugin.cc input_driver.cc object_gc.cc \
input_source.cc session.cc core_api.cc lua_glue.swg.cc
SRC_DATA := mag.lua default.tff
#MODE := shared
STATIC_PLUGINS += mag-input-libinput
STATIC_PLUGINS += mag-input-event
STATIC_PLUGINS += mag-client_fb
STATIC_PLUGINS += mag-mag_client
REQUIRES_LIBS:= libsupc++ libdl mag-gfx lua++ cxx_libc_io cxx_io
REQUIRES_LIBS += $(STATIC_PLUGINS)
#LDFLAGS += --export-dynamic
CPPFLAGS += -fvisibility=hidden
CXXFLAGS_lua_glue.swg.cc += -Wno-misleading-indentation
include $(L4DIR)/mk/prog.mk
# regenerate shipped files
ifneq ($(REGEN_FILES),)
all:: $(SRC_DIR)/lua_glue.swg.h $(SRC_DIR)/lua_glue.swg.cc
SWIG_RM_EXT_C ?= $(L4DIR)/tool/bin/swig-rm-extern-c.pl
SWIG ?= swig
%.swg:
$(SRC_DIR)/%.swg.cc: $(SRC_DIR)/%.swg.c_cc $(SRC_DIR)/Makefile
@$(GEN_MESSAGE)
$(VERBOSE)$(SWIG_RM_EXT_C) $< >$@
$(SRC_DIR)/%.swg.h: $(SRC_DIR)/%.swg.c_h
@$(GEN_MESSAGE)
$(VERBOSE)$(SWIG_RM_EXT_C) $< >$@
SWIG_INCDIR:=-I$(SRC_DIR) -I$(SRC_DIR)/../../include -I$(L4DIR)/pkg
$(SRC_DIR)/%.swg.c_cc: $(SRC_DIR)/%.swg $(SRC_DIR)/Makefile
@$(GEN_MESSAGE)
$(VERBOSE)$(SWIG) $(SWIG_INCDIR) -c++ -small -lua -o $@ $<
$(SRC_DIR)/%.swg.c_h:
@$(GEN_MESSAGE)
$(VERBOSE)$(SWIG) $(SWIG_INCDIR) -c++ -small -lua -external-runtime $@
endif

View File

@@ -0,0 +1,32 @@
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/sys/types.h>
namespace Mag_server
{
class Axis_buf
{
private:
unsigned char s;
l4_int32_t v[4];
public:
Axis_buf(unsigned char _s) : s(_s-1) { assert ((_s & s) == 0); }
l4_int32_t get(unsigned char idx) const { return v[idx & s]; }
void set(unsigned char idx, l4_int32_t val) { v[idx & s] = val; }
void copy(unsigned char idx1, unsigned char idx2)
{ set(idx1, get(idx2)); }
l4_int32_t __getitem__(unsigned char idx) const { return v[idx & s]; }
void __setitem__(unsigned char idx, l4_int32_t val) { v[idx & s] = val; }
};
}

View File

@@ -0,0 +1,34 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag-gfx/canvas>
#include <l4/mag-gfx/clip_guard>
#include "view"
namespace Mag_server {
using namespace Mag_gfx;
class Background : public View
{
public:
explicit Background(Area const &size) : View(Rect(Point(0,0), size)) {}
void draw(Canvas *c, View_stack const *, Mode) const
{
Clip_guard g(c, *this);
c->draw_box(*this, Rgb32::Color(25, 37, 50));
}
void handle_event(Hid_report *, Point const &, bool) {}
};
}

View File

@@ -0,0 +1,42 @@
/*
* (c) 2010 Author(s)
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag-gfx/mem_texture>
#include <l4/mag-gfx/gfx_colors>
#include "big_mouse.h"
/*
* \brief Mouse cursor pixel data
* \author Norman Feske
* \date 2006-08-09
*/
static l4_uint16_t const pixels[16][16] =
{
{0x738E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x94B2,0x7BCF,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x630C,0xC638,0xC638,0x6B4D,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x738E,0x8C71,0xFFFF,0xB5B6,0x6B4D,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x630C,0x4A49,0x630C,0xB5B6,0xFFFF,0xB5B6,0x630C,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x528A,0x528A,0x630C,0x9492,0xB5B6,0xFFFF,0xB5B6,0x630C,0x0000,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x528A,0x39C7,0x4208,0x630C,0x7BCF,0xB5B6,0xFFFF,0xFFFF,0xB5B6,0x630C,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x4208,0x39C7,0x4208,0x630C,0x7BCF,0xB5B6,0xDEFB,0xFFFF,0xFFFF,0xB5B6,0x630C,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x4A49,0x1082,0x39C7,0x4208,0x5ACB,0x7BCF,0x8C71,0xAD75,0x630C,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x0000,0x4208,0x1082,0x39C7,0x5ACB,0x630C,0xB5B6,0x0000,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x1082,0x1082,0x39C7,0x4A49,0x630C,0xAD75,0x0000,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4208,0x1082,0x4A49,0x0000,0x4A49,0x630C,0x8C71,0x0000,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x39C7,0x4A49,0x0000,0x0000,0x4A49,0x630C,0x8C71,0x0000,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x0000,0x0000,0x0000,0x0000,0x4A49,0x630C,0x8C71,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x4A49,0x0000},
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
};
static Mag_gfx::Mem::Texture<Mag_gfx::Rgb16> const __big_mouse(const_cast<Mag_gfx::Rgb16::Pixel*>(reinterpret_cast<Mag_gfx::Rgb16::Pixel const *>(&pixels[0][0])), Mag_gfx::Area(16,16));
Mag_gfx::Texture const *const big_mouse = &__big_mouse;

View File

@@ -0,0 +1,13 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag-gfx/texture>
extern Mag_gfx::Texture const *const big_mouse;

View File

@@ -0,0 +1,47 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag/server/input_source>
#include <l4/mag/server/plugin>
namespace Mag_server {
class Core_api_impl : public Core_api
{
private:
Registry *_reg;
Input_source *_input;
mutable cxx::Notifier _tick_ntfy;
mutable cxx::Notifier _session_ntfy;
mutable Session_list _sessions;
public:
Core_api_impl(Registry *r, lua_State *lua, User_state *u,
L4::Cap<L4Re::Video::Goos> fb,
Mag_gfx::Font const *label_font)
: Core_api(lua, u, fb, label_font), _reg(r), _input(0)
{}
void add_input_source(Input_source *i);
Input_source *input_sources() const { return _input; }
Registry *registry() const { return _reg; }
void get_ticks(cxx::Observer *o) const;
void tick() const { _tick_ntfy.notify(); }
void register_session(Session *) const;
Session_list *sessions() const { return &_sessions; }
void add_session_observer(cxx::Observer *) const;
};
}

View File

@@ -0,0 +1,44 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "core_api"
#include <lua.h>
namespace Mag_server {
void
Core_api_impl::add_input_source(Input_source *i)
{
i->_next_active = _input;
_input = i;
i->add_lua_input_source(lua_state());
}
void
Core_api_impl::register_session(Session *s) const
{
_sessions.push_back(s);
s->set_notifier(&_session_ntfy);
_session_ntfy.notify();
}
void
Core_api_impl::get_ticks(cxx::Observer *o) const
{
_tick_ntfy.add(o);
}
void
Core_api_impl::add_session_observer(cxx::Observer *o) const
{
_session_ntfy.add(o);
}
}

Binary file not shown.

View File

@@ -0,0 +1,10 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "input_driver"

View File

@@ -0,0 +1,53 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "input_source"
#include "plugin"
#include "lua_glue.swg.h"
#include <lua.h>
#include <lauxlib.h>
namespace Mag_server {
void
Input_source::post_event(L4Re::Event_buffer::Event const *e)
{
lua_State *l = _core->lua_state();
lua_getglobal(l, "handle_event");
lua_createtable(l, 6, 0);
lua_pushinteger(l, e->payload.type);
lua_rawseti(l, -2, 1);
lua_pushinteger(l, e->payload.code);
lua_rawseti(l, -2, 2);
lua_pushinteger(l, e->payload.value);
lua_rawseti(l, -2, 3);
lua_pushinteger(l, e->time);
lua_rawseti(l, -2, 4);
lua_pushinteger(l, e->payload.stream_id);
lua_rawseti(l, -2, 5);
lua_rawgeti(l, LUA_REGISTRYINDEX, _ref);
lua_rawseti(l, -2, 6);
if (lua_pcall(l, 1, 0, 0))
{
fprintf(stderr, "ERROR: lua event handling returned: %s.\n", lua_tostring(l, -1));
lua_pop(l, 1);
}
}
void
Input_source::add_lua_input_source(lua_State *l)
{
swig_type_info *type = SWIG_TypeQuery(l, "Mag_server::Input_source *");
assert(type);
SWIG_NewPointerObj(l, this, type, 0);
_ref = luaL_ref(l, LUA_REGISTRYINDEX);
}
}

View File

@@ -0,0 +1,387 @@
// vi:ft=cpp
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
%module Mag
%include <typemaps.i>
%include <lua_typemap.i>
/* typemap for our input values (supporting and invalid value as 'nil') */
%typemap(out) Mag_server::Value<int>
%{ if ($1.valid()) lua_pushinteger(L, $1.val()); else lua_pushnil(L); SWIG_arg++; %}
%typemap(in) Mag_server::Value<int>
%{
if (lua_isnil(L, $input))
$1 = Mag_server::Value<int>();
else
{
SWIG_contract_assert(lua_isinteger(L, $input), "argument must be a number")
$1 = Mag_server::Value<int>(lua_tointeger(L, $input));
}
%}
/* we report key events as pair of code and value in lua */
%typemap(out) Mag_server::Hid_report::Key_event const *
%{
if ($1)
{
lua_pushinteger(L, $1->code);
lua_pushinteger(L, $1->value);
SWIG_arg += 2;
}
%}
%{
#include <l4/mag/server/plugin>
#include <l4/mag/server/hid_report>
#include <l4/mag/server/valuator>
#include <l4/mag/server/user_state>
#include <l4/mag/server/input_source>
#include <l4/mag/server/session>
#include "axis_buf.h"
namespace Mag_server {
extern Mag_server::User_state *user_state;
extern Core_api *core_api;
}
int luaopen_Mag(lua_State*);
static int lua_session_iterator(lua_State *L)
{
using Mag_server::Session;
int b = lua_upvalueindex(1);
int e = lua_upvalueindex(2);
Session *bs, *es;
if (!lua_isuserdata(L, b) || !lua_isuserdata(L, e)
|| SWIG_ConvertPtr(L, b, (void**)&bs, SWIGTYPE_p_Mag_server__Session, 0) == -1
|| SWIG_ConvertPtr(L, e, (void**)&es, SWIGTYPE_p_Mag_server__Session, 0) == -1)
return 0;
if (bs == es)
return 0;
lua_pushvalue(L, b);
bs = static_cast<Session*>(cxx::D_list_item_policy::next(bs));
SWIG_NewPointerObj(L, bs, SWIGTYPE_p_Mag_server__Session, 0);
lua_replace(L, b);
return 1;
}
%}
%ignore Mag_server::View_proxy::view;
%ignore Mag_server::View_proxy::forget;
%ignore Mag_server::View;
%ignore Mag_server::User_state::User_state;
%ignore Mag_server::User_state::forget_view;
%ignore Mag_server::Mode;
%ignore L4Re::Event;
%ignore L4Re::Default_event_payload;
%ignore L4Re::Event_buffer_t;
%ignore L4Re::Event_buffer;
#pragma SWIG nowarn=401,325
#define L4_EXPORT
#define L4_KOBJECT(x)
%nodefaultctor;
%nodefaultdtor;
%ignore Mag_server::Session::Property_handler;
%ignore cxx::String;
%ignore Mag_server::Session_list;
%ignore cxx::D_list<Mag_server::Session>;
%ignore Mag_server::Session::set_label_prop;
%ignore Mag_server::Session::set_color_prop;
%ignore Mag_server::Session::color;
%ignore Mag_server::Session::set_notifier;
%ignore Mag_server::Session::background;
%include <server/session>
%clearnodefaultctor;
%clearnodefaultdtor;
%include <server/mode>
%include <server/valuator>
%apply unsigned *OUTPUT { unsigned *bus, unsigned *vendor, unsigned *product, unsigned *version };
#define L4_RPC(a, b, c...)
#define L4_RPC_NF(a, b, c...)
%include <l4re-core/l4re/include/event>
%clear unsigned *bus, unsigned *vendor, unsigned *product, unsigned *version;
%include <axis_buf.h>
%template(Valuatori) Mag_server::Valuator<int>;
%template(Valuei) Mag_server::Value<int>;
namespace Mag_server {
class Axis_info
{
public:
int value;
int min;
int max;
int fuzz;
int flat;
int resolution;
int delta;
int mode;
};
class Axis_info_vector
{
public:
Axis_info_vector();
explicit Axis_info_vector(unsigned size);
~Axis_info_vector();
unsigned size() const;
Axis_info const *get(unsigned idx) const;
Axis_info *get(unsigned idx);
Axis_info *create(unsigned idx);
%apply SWIGTYPE *DISOWN { Axis_info *info };
bool set(unsigned idx, Axis_info *info);
%clear Axis_info *info;
};
%extend Axis_info_vector
{
Mag_server::Axis_info *__getitem__(unsigned idx)
{
return self->get(idx);
}
};
class Hid_report
{
public:
struct Key_event;
Hid_report(l4_umword_t device_id, unsigned rels, unsigned abss, unsigned mscs,
unsigned sws, unsigned mts);
~Hid_report();
bool get(unsigned char type, unsigned code, int &val) const;
void set(unsigned char type, unsigned code, int val);
bool mt_get(unsigned id, unsigned code, int &val) const;
void mt_set(unsigned code, int val);
bool submit_mt();
Valuator<int> const *get_vals(unsigned char type) const;
Valuator<int> *get_vals(unsigned char type);
Valuator<int> const *get_mt_vals(unsigned id) const;
bool add_key(int code, int value);
Key_event const *get_key_event(unsigned idx) const;
Key_event const *find_key_event(int code) const;
void remove_key_event(int code);
void sync(long long time);
long long time() const;
void clear();
l4_umword_t device_id() const;
Axis_info_vector const *abs_infos() const;
Axis_info_vector *abs_infos();
void set_abs_info(Axis_info_vector *i);
};
}
%extend Mag_server::Valuator<int>
{
Mag_server::Value<int> __getitem__(unsigned idx) const
{
return self->get(idx);
}
void __setitem__(unsigned idx, Mag_server::Value<int> v)
{
if (v.valid())
self->set(idx, v.val());
else
self->inv(idx);
}
}
%extend Mag_server::Hid_report
{
Mag_server::Valuator<int> *__getitem__(unsigned char type)
{
return self->get_vals(type);
}
};
%nodefaultctor;
class Mag_server::User_state
{
public:
void set_pointer(int x, int y, bool hide);
};
class Mag_server::View_proxy
{
public:
View_proxy(Mag_server::User_state *ust);
};
%clearnodefaultctor;
%extend Mag_server::User_state
{
bool set_kbd_focus(Mag_server::View_proxy *vp)
{
if (!vp)
return self->set_focus(0);
else
return self->set_focus(vp->view());
}
void post_event(Mag_server::View_proxy *vp, Mag_server::Hid_report *e, bool update,
bool core_ev)
{
Mag_server::View *v = vp ? vp->view() : self->kbd_focus();
if (update)
self->vstack()->update_all_views();
//maybe_screenshot(ust, e);
if (v && (!self->vstack()->mode().kill() || v->super_view()))
v->handle_event(e, self->mouse_pos(), core_ev);
}
void toggle_mode(Mag_server::Mode::Mode_flag mode)
{
self->vstack()->toggle_mode(mode);
}
void find_pointed_view(Mag_server::View_proxy *vp)
{
if (!vp)
return;
vp->view(self->vstack()->find(self->mouse_pos()));
}
%apply int *OUTPUT {int *w, int *h};
void screen_size(int *w, int *h)
{
Mag_gfx::Area s = self->vstack()->canvas()->size();
*w = s.w();
*h = s.h();
}
};
%extend Mag_server::View_proxy
{
void set(Mag_server::View_proxy *src)
{
self->view(src ? src->view() : 0);
}
};
%nodefaultctor;
%typemap(in) l4_umword_t USERDATA;
%typemap(in,checkfn="lua_isuserdata") l4_umword_t USERDATA
%{ $1 = (l4_umword_t)lua_touserdata(L, $input); %}
class Mag_server::Input_source
{};
%extend Mag_server::Input_source
{
public:
int get_stream_info(l4_umword_t id, L4Re::Event_stream_info **OUTPUT)
{
*OUTPUT = new L4Re::Event_stream_info();
return self->get_stream_info(id, *OUTPUT);
}
int get_abs_info(l4_umword_t id, unsigned axis, Mag_server::Axis_info **OUTPUT)
{
*OUTPUT = 0;
unsigned axes[1];
axes[0] = axis;
L4Re::Event_absinfo info[1];
int res = self->get_axis_info(id, 1, axes, info);
if (res < 0)
return res;
Mag_server::Axis_info *i = new Mag_server::Axis_info();
*OUTPUT = i;
i->value = info->value;
i->min = info->min;
i->max = info->max;
i->fuzz = info->fuzz;
i->flat = info->flat;
i->resolution = info->resolution;
i->delta = info->max - info->min;
i->mode = 0;
return res;
}
};
namespace Mag_server {
%typemap(out) Session_list * {
SWIG_NewPointerObj(L, *($1->begin()), SWIGTYPE_p_Mag_server__Session, 0);
SWIG_NewPointerObj(L, *($1->end()), SWIGTYPE_p_Mag_server__Session, 0);
lua_pushcclosure(L, &lua_session_iterator, 2);
return 1;
}
%nodefaultctor Core_api;
%nodefaultdtor Core_api;
class Core_api
{
public:
Session_list *sessions() const;
};
%immutable;
extern Core_api *core_api;
%mutable;
}
%clearnodefaultctor;
%extend L4Re::Event_stream_info
{
public:
void get_device_id(unsigned *bus, unsigned *vendor, unsigned *product, unsigned *version)
{
*bus = self->id.bustype;
*vendor = self->id.vendor;
*product = self->id.product;
*version = self->id.version;
}
};
%inline %{
static Mag_server::User_state *get_user_state()
{
return Mag_server::user_state;
}
%}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
// vi:ft=cpp
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
%{
#define SWIG_RECURSIVE_DEFINED defined
%}
%define SWIG_INTEGER_TYPEMAP(TYPE)
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) TYPE
{$1 = lua_isinteger(L, $input);}
%typemap(in,checkfn="lua_isinteger") TYPE
%{ $1 = ($type)lua_tointeger(L, $input); %}
%typemap(in,checkfn="lua_isinteger") TYPE *INPUT($*ltype temp), TYPE &INPUT($*ltype temp)
%{ temp = ($*ltype)lua_tointeger(L,$input);
$1 = &temp; %}
%typemap(in, numinputs=0) TYPE *OUTPUT ($*ltype temp)
%{ $1 = &temp; %}
%typemap(argout) TYPE *OUTPUT
%{ lua_pushinteger(L, (lua_Integer) *$1); SWIG_arg++;%}
%typemap(in) TYPE *INOUT = TYPE *INPUT;
%typemap(argout) TYPE *INOUT = TYPE *OUTPUT;
%typemap(in) TYPE &OUTPUT = TYPE *OUTPUT;
%typemap(argout) TYPE &OUTPUT = TYPE *OUTPUT;
%typemap(in) TYPE &INOUT = TYPE *INPUT;
%typemap(argout) TYPE &INOUT = TYPE *OUTPUT;
// const version (the $*ltype is the basic number without ptr or const's)
%typemap(in,checkfn="lua_isinteger") const TYPE *INPUT($*ltype temp)
%{ temp = ($*ltype)lua_tointeger(L,$input);
$1 = &temp; %}
%typemap(out) TYPE
%{ lua_pushinteger(L, (lua_Integer)($1)); SWIG_arg++; %}
%enddef
SWIG_INTEGER_TYPEMAP(l4_mword_t); SWIG_INTEGER_TYPEMAP(l4_umword_t);
SWIG_INTEGER_TYPEMAP(l4_int32_t); SWIG_INTEGER_TYPEMAP(l4_uint32_t);
SWIG_INTEGER_TYPEMAP(l4_int64_t); SWIG_INTEGER_TYPEMAP(l4_uint64_t);
SWIG_INTEGER_TYPEMAP(int); SWIG_INTEGER_TYPEMAP(unsigned);
SWIG_INTEGER_TYPEMAP(long int); SWIG_INTEGER_TYPEMAP(unsigned long);
SWIG_INTEGER_TYPEMAP(long long int); SWIG_INTEGER_TYPEMAP(unsigned long long);
SWIG_INTEGER_TYPEMAP(short int); SWIG_INTEGER_TYPEMAP(unsigned short);
SWIG_INTEGER_TYPEMAP(char); SWIG_INTEGER_TYPEMAP(unsigned char); SWIG_INTEGER_TYPEMAP(signed char);
SWIG_INTEGER_TYPEMAP(l4_addr_t);
/* Refined typemaps for our L4 types and our lua lib with integer support */
/*
%typemap(in,checkfn="lua_isnumber") l4_int32_t, l4_int64_t, int, short, long, signed char, long long
%{$1 = ($type)lua_tointeger(L, $input);%}
%typemap(in,checkfn="lua_isnumber") l4_umword_t, l4_uint64_t,unsigned long long,
unsigned int, unsigned short,
unsigned long, unsigned char
%{SWIG_contract_assert((lua_tointeger(L,$input)>=0),"number must not be negative")
$1 = ($type)lua_tointeger(L, $input);%}
*/
%typemap(in,checkfn="lua_isinteger") enum SWIGTYPE
%{$1 = ($type)(int)lua_tointeger(L, $input);%}
%typemap(out) enum SWIGTYPE
%{ lua_pushinteger(L, (lua_Integer)($1)); SWIG_arg++;%}
/*
%typemap(out) long long, l4_umword_t,l4_int32_t,l4_int64_t,int,short,long,
unsigned long long, l4_uint32_t, l4_uint64_t,
unsigned int,unsigned short,unsigned long,
signed char,unsigned char
%{ lua_pushinteger(L, $1); SWIG_arg++;%}
%typemap(out) l4_int32_t*,l4_int64_t*,int*,short*,long*,
l4_uint32_t *, l4_uint64_t *, long long *, unsigned long long*,
unsigned int*,unsigned short*,unsigned long*,
signed char*,unsigned char*
%{ lua_pushinteger(L, *$1); SWIG_arg++;%}
*/
%typemap(typecheck,precedence=SWIG_TYPECHECK_STRING) cxx::String, cxx::String const & {
$1 = lua_isstring(L, $input);
}
%typemap(in,checkfn="lua_isstring") cxx::String
%{$1 = cxx::String(lua_tostring(L, $input), lua_rawlen(L, $input));%}
%typemap(in,checkfn="lua_isstring") cxx::String const & (cxx::String tmp)
%{tmp = cxx::String(lua_tostring(L, $input), lua_rawlen(L, $input)); $1 = &tmp;%}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,358 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag-gfx/geometry>
#include <l4/mag-gfx/canvas>
#include "factory"
#include <l4/util/util.h>
#include <l4/cxx/iostream>
#include <l4/cxx/exceptions>
#include <l4/re/util/cap_alloc>
#include <l4/re/error_helper>
#include <l4/re/env>
#include <l4/re/rm>
#include <l4/re/video/goos>
#include <l4/re/util/video/goos_fb>
#include <l4/re/util/br_manager>
#include <l4/re/util/debug>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <terminate_handler-l4>
#include "background.h"
#include "big_mouse.h"
#include "input_driver"
#include "object_gc.h"
#include "core_api"
#include <dlfcn.h>
using namespace Mag_server;
extern char const _binary_mag_lua_start[];
extern char const _binary_mag_lua_end[];
extern char const _binary_default_tff_start[];
namespace Mag_server {
Core_api_impl *core_api;
class Plugin_manager
{
public:
static void start_plugins(Core_api *core)
{
for (Plugin *p = Plugin::_first; p; p = p->_next)
if (!p->started())
p->start(core);
}
};
}
namespace {
class My_reg : public Registry, private Object_gc
{
private:
My_reg(My_reg const &);
void operator = (My_reg const &);
class Del_handler : public L4::Irqep_t<Del_handler>
{
private:
Object_gc *gc;
public:
explicit Del_handler(Object_gc *gc) : gc(gc) {}
void handle_irq()
{ gc->gc_step(); }
};
L4::Cap<L4::Irq> _del_irq;
public:
My_reg(L4::Ipc_svr::Server_iface *sif) : Registry(sif)
{
_del_irq = register_irq_obj(new Del_handler(this));
assert (_del_irq);
_server->register_del_irq(_del_irq);
};
void add_gc_obj(Object *o)
{
Object_gc::add_obj(o);
}
void gc_obj(Object *o)
{
unregister_obj(o);
}
};
static void
poll_input(Core_api_impl *core)
{
for (Input_source *i = core->input_sources(); i; i = i->next())
i->poll_events();
}
class Loop_hooks : public L4::Ipc_svr::Ignore_errors,
public L4Re::Util::Br_manager
{
public:
l4_kernel_clock_t to;
Loop_hooks()
{
to = l4_kip_clock(l4re_kip()) + 40000;
}
l4_timeout_t timeout()
{ return l4_timeout(L4_IPC_TIMEOUT_0, l4_timeout_abs(to, 8)); }
void setup_wait(l4_utcb_t *utcb, L4::Ipc_svr::Reply_mode reply_mode)
{
if (to <= l4_kip_clock(l4re_kip())
&& reply_mode == L4::Ipc_svr::Reply_separate)
{
poll_input(core_api);
core_api->user_state()->vstack()->flush();
core_api->tick();
to += 40000;
while (to - 10000 < l4_kip_clock(l4re_kip()))
to += 20000;
}
Br_manager::setup_wait(utcb, reply_mode);
}
L4::Ipc_svr::Reply_mode before_reply(l4_msgtag_t, l4_utcb_t *)
{
if (to <= l4_kip_clock(l4re_kip()))
return L4::Ipc_svr::Reply_separate;
return L4::Ipc_svr::Reply_compound;
}
};
static L4::Server<Loop_hooks> server;
static My_reg registry(&server);
using L4Re::chksys;
using L4Re::chkcap;
#if 0
static void test_texture(Texture *t)
{
char *tb = (char *)t->pixels();
for (int y = 0; y < t->size().h(); ++y)
for (int x = 0; x < t->size().w(); ++x)
{
t->type()->set(tb, Pixel_info::Col(x*400, y*300, x*y, 0));
tb += t->type()->bytes;
}
}
#endif
int load_lua_plugin(Core_api *core_api, char const *name)
{
char const *n = name;
if (access(n, F_OK) != 0)
return 1;
printf("loading '%s'\n", n);
lua_State *_l = core_api->lua_state();
int err = luaL_dofile(_l, n);
if (err)
{
printf("ERROR: loading '%s': %s\n", n, lua_tostring(_l, -1));
lua_pop(_l, lua_gettop(_l));
return -1;
}
lua_pop(_l, lua_gettop(_l));
return 0;
}
int load_so_plugin(Core_api *core_api, char const *name)
{
static char const *const pfx = "libmag-";
static char const *const sfx = ".so";
char *n = new char [strlen(name) + strlen(pfx) + strlen(sfx) + 1];
strcpy(n, pfx);
strcpy(n + strlen(pfx), name);
strcpy(n + strlen(pfx) + strlen(name), sfx);
printf("loading '%s'\n", n);
void *pl = dlopen(n, RTLD_LAZY);
if (!pl)
{
printf("ERROR: loading '%s': %s\n", n, dlerror());
delete [] n;
return -1;
}
else
{
void (*ini)(Core_api*) = (void (*)(Core_api*))dlsym(pl, "init_plugin");
ini(core_api);
}
delete [] n;
return 0;
}
static const luaL_Reg libs[] =
{
{ "_G", luaopen_base },
{LUA_LOADLIBNAME, luaopen_package},
// { LUA_IOLIBNAME, luaopen_io },
{ LUA_STRLIBNAME, luaopen_string },
{LUA_LOADLIBNAME, luaopen_package},
{LUA_DBLIBNAME, luaopen_debug},
{LUA_TABLIBNAME, luaopen_table},
{ NULL, NULL }
};
struct Err : L4Re::Util::Err { Err() : L4Re::Util::Err(Fatal, "") {} };
}
int main(int argc, char const *argv[])
{
L4Re::Util::Dbg dbg;
Err p_err;
dbg.printf("Hello from MAG\n");
L4Re::Env const *env = L4Re::Env::env();
L4::Cap<L4Re::Video::Goos> fb
= chkcap(env->get_cap<L4Re::Video::Goos>("fb"), "requesting frame-buffer", 0);
L4Re::Util::Video::Goos_fb goos_fb;
chksys(goos_fb.init(fb), "init frame-buffer");
L4Re::Video::View::Info view_i;
chksys(goos_fb.view_info(&view_i), "requesting frame-buffer info");
L4Re::Rm::Unique_region<char *> fb_addr;
chksys(env->rm()->attach(&fb_addr, goos_fb.buffer()->size(),
L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
L4::Ipc::make_cap_rw(goos_fb.buffer()),
0, L4_SUPERPAGESHIFT));
dbg.printf("mapped frame buffer at %p\n", fb_addr.get());
Screen_factory *f = dynamic_cast<Screen_factory*>(Screen_factory::set.find(view_i.pixel_info));
if (!f)
{
printf("ERROR: could not start screen driver for given video mode.\n"
" Maybe unsupported pixel format... exiting\n");
exit(1);
}
Canvas *screen = f->create_canvas(fb_addr.get() + view_i.buffer_offset,
Area(view_i.width, view_i.height), view_i.bytes_per_line);
view_i.dump(dbg);
dbg.printf(" memory %p - %p\n", (void*)fb_addr.get(),
(void*)(fb_addr.get() + goos_fb.buffer()->size()));
if (!screen)
{
p_err.printf("ERROR: could not start screen driver for given video mode.\n"
" Maybe unsupported pixel format... exiting\n");
exit(1);
}
View *cursor = f->create_cursor(big_mouse);
Background bg(screen->size());
L4Re::Video::View *screen_view = 0;
{
L4Re::Video::Goos::Info i;
goos_fb.goos()->info(&i);
if (!i.auto_refresh())
screen_view = goos_fb.view();
}
lua_State *lua = luaL_newstate();
if (!lua)
{
p_err.printf("ERROR: cannot allocate Lua state\n");
exit(1);
}
lua_newtable(lua);
lua_setglobal(lua, "Mag");
for (int i = 0; libs[i].func; ++i)
{
luaL_requiref(lua, libs[i].name, libs[i].func, 1);
lua_pop(lua, 1);
}
static Font label_font(&_binary_default_tff_start[0]);
static View_stack vstack(screen, screen_view, &bg, &label_font);
static User_state user_state(lua, &vstack, cursor);
static Core_api_impl core_api(&registry, lua, &user_state, fb, &label_font);
Mag_server::core_api = &core_api;
int err;
if ((err = luaL_loadbuffer(lua, _binary_mag_lua_start, _binary_mag_lua_end - _binary_mag_lua_start, "@mag.lua")))
{
p_err.printf("lua error: %s.\n", lua_tostring(lua, -1));
lua_pop(lua, lua_gettop(lua));
if (err == LUA_ERRSYNTAX)
throw L4::Runtime_error(L4_EINVAL, lua_tostring(lua, -1));
else
throw L4::Out_of_memory(lua_tostring(lua, -1));
}
if ((err = lua_pcall(lua, 0, 1, 0)))
{
p_err.printf("lua error: %s.\n", lua_tostring(lua, -1));
lua_pop(lua, lua_gettop(lua));
if (err == LUA_ERRSYNTAX)
throw L4::Runtime_error(L4_EINVAL, lua_tostring(lua, -1));
else
throw L4::Out_of_memory(lua_tostring(lua, -1));
}
lua_pop(lua, lua_gettop(lua));
Plugin_manager::start_plugins(&core_api);
for (int i = 1; i < argc; ++i)
{
if (load_lua_plugin(&core_api, argv[i]) == 1)
load_so_plugin(&core_api, argv[i]);
}
server.loop<L4::Runtime_error>(&registry);
return 0;
}

View File

@@ -0,0 +1,42 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag-gfx/clip_guard>
#include <l4/mag-gfx/mem_texture>
#include "view_stack"
#include "view"
namespace Mag_server {
using namespace Mag_gfx;
template< typename PT >
class Mouse_cursor : public View
{
private:
Mem::Texture<PT> const *_t;
public:
Mouse_cursor(Texture const *t)
: View(Rect(Point(0,0), t->size()), F_transparent),
_t(static_cast<Mem::Texture<PT> const *>(t))
{}
void draw(Canvas *canvas, View_stack const *, Mode) const
{
Clip_guard g(canvas, *this);
canvas->draw_texture(_t, Rgb32::Black, p1(), Canvas::Masked);
}
void handle_event(Hid_report *, Point const &, bool) {}
};
}

View File

@@ -0,0 +1,53 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "object_gc.h"
#include <cstdio>
namespace Mag_server {
void
Object_gc::gc_step()
{
//printf("GC: step this=%p _life = %p\n", this, _life.front());
for (Obj_iter n = _life.begin(); n != _life.end();)
{
if (!n->obj_cap() || !n->obj_cap().validate().label())
{
//printf("GC: object=%p\n", *n);
gc_obj(*n);
Object *o = *n;
n = _life.erase(n);
o->destroy();
// drop the reference held in the IPC gate
cxx::Ref_ptr<Object> p(o, true);
}
else
++n;
}
}
void
Object_gc::gc_sweep()
{
for (;;)
{
Obj_iter o = _sweep.begin();
if (o == _sweep.end())
break;
Object *x = *o;
_sweep.erase(o);
printf("GC: delete object %p\n", x);
delete x;
}
}
}

View File

@@ -0,0 +1,40 @@
// vi:ft=cpp
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#pragma once
#include <l4/mag/server/object>
namespace Mag_server {
class Object_gc
{
private:
Object_gc(Object_gc const &);
void operator = (Object_gc const &);
protected:
typedef cxx::H_list<Object> Obj_list;
typedef Obj_list::Iterator Obj_iter;
Obj_list _life;
Obj_list _sweep;
public:
Object_gc() {}
void gc_sweep();
void gc_step();
void add_obj(Object *o) { o->enqueue(&_life); }
virtual void gc_obj(Object *o) = 0;
};
}

View File

@@ -0,0 +1,85 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "plugin"
#include <lua.h>
#include <lauxlib.h>
#include <l4/cxx/string>
#include <l4/mag/server/session>
#include <l4/re/error_helper>
#include <algorithm>
#include <cstring>
namespace Mag_server {
Plugin *Plugin::_first;
Core_api::Core_api(lua_State *lua, User_state *u,
L4::Cap<L4Re::Video::Goos> fb,
Mag_gfx::Font const *label_font)
: _ust(u), _fb(fb), _lua(lua), _label_font(label_font)
{
}
namespace {
Session::Property_handler const _default_session_props[] =
{ { "l", true, &Session::set_label_prop },
{ "label", true, &Session::set_label_prop },
{ "col", true, &Session::set_color_prop },
{ 0, 0, 0 }
};
static bool handle_option(Session *s, Session::Property_handler const *p, cxx::String const &a)
{
for (; p && p->tag; ++p)
{
cxx::String::Index v = a.starts_with(p->tag);
if (v && (!p->value_property || a[v] == '='))
{
p->handler(s, p, a.substr(v + 1));
return true;
}
}
return false;
}
}
void
Core_api::set_session_options(Session *s, L4::Ipc::Varg_list_ref args,
Session::Property_handler const *extra) const
{
for (L4::Ipc::Varg opt: args)
{
if (!opt.is_of<char const *>())
{
printf("skipping non string argument for session!\n");
continue;
}
// opt without zero terminator
cxx::String a(opt.value<char const *>(), opt.length() - 1);
if (!handle_option(s, _default_session_props, a)
&& !handle_option(s, extra, a))
{
printf("unknown session option '%.*s'\n", a.len(), a.start());
L4Re::chksys(-L4_EINVAL, "parsing session options");
}
}
if (!s->label())
s->set_label_prop(s, 0, "<empty>");
}
}

View File

@@ -0,0 +1,50 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "factory"
#include <l4/mag-gfx/mem_factory>
#include "mouse_cursor.h"
namespace Mag_server {
using namespace Mag_gfx;
template< typename PT >
class Csf : public Screen_factory, public Mem::Factory<PT>
{
public:
View *create_cursor(Texture const *cursor)
{
typedef typename PT::Pixel Pixel;
if (cursor->type() == PT::type())
return new Mouse_cursor<PT>(cursor);
else
{
void *m = malloc(cursor->size().pixels() * sizeof(Pixel));
Texture *c = new Mem::Texture<PT>((Pixel*)m, cursor->size());
c->blit(cursor);
return new Mouse_cursor<PT>(c);
}
}
};
static Csf<Rgb15> _csf_rgb15;
static Csf<Bgr15> _csf_bgr15;
static Csf<Rgb16> _csf_rgb16;
static Csf<Bgr16> _csf_bgr16;
static Csf<Rgb24> _csf_rgb24;
static Csf<Rgb32> _csf_rgb32;
static Csf<Bgr32> _csf_bgr32;
static Csf<Rgba32> _csf_rgba32;
}

View File

@@ -0,0 +1,71 @@
#include <l4/mag/server/session>
#include <algorithm>
#include <cstring>
void
Mag_server::Session::set_label_prop(Session *s, Property_handler const *, cxx::String const &v)
{
if (s->_label)
delete [] s->_label;
if (v.empty())
{
s->_label = 0;
return;
}
// limit label length to 256 letters
unsigned l = std::min(v.len(), 256);
s->_label = new char[l + 1];
memcpy(s->_label, v.start(), l);
s->_label[l] = 0;
}
void
Mag_server::Session::set_color_prop(Session *s, Property_handler const *, cxx::String const &v)
{
typedef Mag_gfx::Rgb32::Color Color;
if (v.empty())
return;
l4_uint32_t cval;
if (v.eof(v.start() + v.from_hex(&cval)))
{
s->_color = Color((cval >> 16) & 0xff, (cval >> 8) & 0xff, cval & 0xff);
return;
}
switch (v[0])
{
case 'r': s->_color = Color(130, 0, 0); break;
case 'g': s->_color = Color(0, 130, 0); break;
case 'b': s->_color = Color(0, 0, 130); break;
case 'w': s->_color = Color(130, 130, 130); break;
case 'y': s->_color = Color(130, 130, 0); break;
case 'v': s->_color = Color(130, 0, 130); break;
case 'R': s->_color = Color(255, 0, 0); break;
case 'G': s->_color = Color(0, 255, 0); break;
case 'B': s->_color = Color(0, 0, 255); break;
case 'W': s->_color = Color(255, 255, 255); break;
case 'Y': s->_color = Color(255, 255, 0); break;
case 'V': s->_color = Color(255, 0, 255); break;
default: s->_color = Color(20, 20, 20); break;
// case 'b': _color = Color(20, 20, 20); break;
}
}
Mag_server::Session::~Session()
{
if (_label)
delete [] _label;
if (cxx::D_list_cyclic<Session>::in_list(this))
cxx::D_list_cyclic<Session>::remove(this);
if (_ntfy)
_ntfy->notify();
}

View File

@@ -0,0 +1,535 @@
/*
* (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include "input_source"
#include "user_state"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <l4/cxx/exceptions>
#include <l4/re/event_enums.h>
#include <errno.h>
#include <cstring>
#include "lua_glue.swg.h"
//#define CONFIG_SCREENSHOT
#if defined (CONFIG_SCREENSHOT)
# include <zlib.h>
namespace {
using namespace Mag_server;
static void base64_encodeblock(char const *_in, char *out)
{
unsigned char const *in = (unsigned char const *)_in;
out[0] = (in[0] >> 2) + ' ';
out[1] = (((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) + ' ';
out[2] = (((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) + ' ';
out[3] = (in[2] & 0x3f) + ' ';
}
static void uuencode(char const *in, unsigned long bytes)
{
char uubuf[100];
char *out;
while (bytes)
{
unsigned cnt = 0;
out = uubuf;
while (bytes)
{
unsigned n = 3;
if (bytes < n)
n = bytes;
if (cnt + n > 45)
break;
base64_encodeblock(in, out);
in += 3;
out += 4;
bytes -= n;
cnt += n;
}
*out = 0;
printf("%c%s\n", cnt + ' ', uubuf);
}
}
static void maybe_screenshot(User_state *ust, User_state::Event const &e)
{
if (e.payload.type != L4RE_EV_KEY || e.payload.value != 1
|| e.payload.code != L4RE_KEY_F12)
return;
char obuf[1024];
int flush;
printf("Start screen shot ==========================\n");
printf("begin 600 screenshot.Z\n");
z_stream s;
s.zalloc = Z_NULL;
s.zfree = Z_NULL;
s.opaque = Z_NULL;
s.next_in = (Bytef*)ust->vstack()->canvas()->buffer();
s.avail_in = ust->vstack()->canvas()->size().h() * ust->vstack()->canvas()->bytes_per_line();
s.total_in = s.avail_in;
s.total_out = 0;
deflateInit2(&s, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY);
do
{
flush = s.avail_in ? Z_NO_FLUSH : Z_FINISH;
do
{
s.next_out = (Bytef*)obuf;
s.avail_out = sizeof(obuf);
if (deflate(&s, flush) == Z_STREAM_ERROR)
{
printf("\nERROR: compressing screenshot\n");
break;
}
unsigned b = sizeof(obuf) - s.avail_out;
if (b)
uuencode(obuf, b);
}
while (s.avail_out == 0);
}
while (flush != Z_FINISH); //s.avail_out == 0);
deflateEnd(&s);
printf(" \nend\n");
printf("\nEND screen shot ==========================\n");
}
}
#else
inline void maybe_screenshot(Mag_server::User_state *, Mag_server::User_state::Event const &) {}
#endif
int luaopen_Mag(lua_State*);
namespace Mag_server {
User_state *user_state;
Hid_report::Hid_report(l4_umword_t dev_id, unsigned rels, unsigned abss, unsigned mscs,
unsigned sws, unsigned mts)
: _device_id(dev_id), _kevs(0), _abs_info(0)
{
_vals[0].create(rels, 0);
_vals[1].create(abss, 0);
_vals[2].create(mscs, 0);
_vals[3].create(sws, 0);
_mts = 0;
if (mts)
{
_mts = mts + 1;
_mt = new Valuator<int>[_mts];
}
for (unsigned i = 0; i < _mts; ++i)
_mt[i].create(Num_mt_vals, Mt_val_offset); // 13 mt axes, currently
}
Hid_report::~Hid_report()
{
if (_mts)
delete [] _mt;
}
void
Hid_report::clear()
{
for (unsigned i = 0; i < Num_types; ++i)
_vals[i].clear();
for (unsigned i = 0; i < _mts; ++i)
_mt[i].clear();
_kevs = 0;
}
Valuator<int> const *
Hid_report::get_vals(unsigned char type) const
{
// check for out of range...
if (type < Type_offset || (type = type - Type_offset) >= Num_types)
return 0;
return &_vals[type];
}
Valuator<int> *
Hid_report::get_vals(unsigned char type)
{
// check for out of range...
if (type < Type_offset || (type = type - Type_offset) >= Num_types)
return 0;
return &_vals[type];
}
Valuator<int> const *
Hid_report::get_mt_vals(unsigned id) const
{
if (_mts && id < _mts - 1)
return &_mt[id];
return 0;
}
bool
Hid_report::get(unsigned char type, unsigned code, int &val) const
{
// check for out of range...
if (type < Type_offset || (type = type - Type_offset) >= Num_types)
return false;
if (!_vals[type].valid(code))
return false;
val = _vals[type][code].val();
return true;
}
void
Hid_report::set(unsigned char type, unsigned code, int val)
{
// check for out of range...
if (type < Type_offset || (type = type - Type_offset) >= Num_types)
return;
_vals[type].set(code, val);
}
bool
Hid_report::mt_get(unsigned id, unsigned code, int &val) const
{
if (id >= _mts)
return false;
if (!_mt[id].valid(code))
return false;
val = _mt[id][code].val();
return true;
}
void
Hid_report::mt_set(unsigned code, int val)
{
if (!_mts)
return;
_mt[_mts-1].set(code, val);
}
bool
Hid_report::submit_mt()
{
if (!_mts)
return false;
Valuator<int> &s = _mt[_mts-1];
Value<int> id = s[0x39];
if (!id.valid())
{
s.clear();
return false;
}
if (id.val() >= (long)_mts - 1)
{
s.clear();
return false;
}
_mt[id.val()].swap(s);
return true;
}
bool
Hid_report::add_key(int code, int value)
{
if (_kevs >= Num_key_events)
return false;
_kev[_kevs].code = code;
_kev[_kevs].value = value;
++_kevs;
return true;
}
Hid_report::Key_event const *
Hid_report::get_key_event(unsigned idx) const
{
if (idx < _kevs)
return _kev + idx;
return 0;
}
Hid_report::Key_event const *
Hid_report::find_key_event(int code) const
{
for (unsigned i = 0; i < _kevs; ++i)
if (_kev[i].code == code)
return _kev + i;
return 0;
}
void
Hid_report::remove_key_event(int code)
{
unsigned i;
for (i = 0; i < _kevs && _kev[i].code != code; ++i)
;
if (i >= _kevs)
return;
memmove(_kev + i, _kev + i + 1, (_kevs - i - 1) * sizeof(Key_event));
--_kevs;
}
void
User_state::set_pointer(int x, int y, bool hide)
{
Point p(x, y);
Rect scr(Point(0, 0), vstack()->canvas()->size());
p = p.min(scr.p2());
p = p.max(scr.p1());
_mouse_pos = p;
if (hide && _mouse_cursor->x1() < scr.x2())
vstack()->viewport(_mouse_cursor, Rect(scr.p2(), _mouse_cursor->size()), true);
if (!hide && _mouse_cursor->p1() != _mouse_pos)
vstack()->viewport(_mouse_cursor, Rect(_mouse_pos, _mouse_cursor->size()), true);
}
#if 0
static void dump_stack(lua_State *l)
{
int i = lua_gettop(l);
while (i)
{
int t = lua_type(l, i);
switch (t)
{
case LUA_TSTRING:
printf("#%02d: '%s'\n", i, lua_tostring(l, i));
break;
case LUA_TBOOLEAN:
printf("#%02d: %s\n", i, lua_toboolean(l, i) ? "true" : "false");
break;
case LUA_TNUMBER:
printf("#%02d: %g\n", i, lua_tonumber(l, i));
break;
default:
printf("#%02d: [%s] %p\n", i, lua_typename(l, t), lua_topointer(l, i));
break;
}
--i;
}
}
#endif
User_state::User_state(lua_State *lua, View_stack *_vstack, View *cursor)
: _vstack(_vstack), _mouse_pos(0,0), _keyboard_focus(0),
_mouse_cursor(cursor), _l(lua)
{
user_state = this;
if (_mouse_cursor)
{
vstack()->push_top(_mouse_cursor, true);
Point pos(vstack()->canvas()->size());
vstack()->viewport(_mouse_cursor, Rect(pos, _mouse_cursor->size()), true);
}
vstack()->update_all_views();
luaopen_Mag(lua);
}
User_state::~User_state()
{
user_state = 0;
}
void
User_state::forget_view(View *v)
{
vstack()->forget_view(v);
for (View_proxy *p = _view_proxies; p; p = p->_n)
p->forget(v);
if (_keyboard_focus == v)
_keyboard_focus = 0;
if (_vstack->focused() == v)
{
_vstack->set_focused(0);
_vstack->update_all_views();
}
}
bool
User_state::set_focus(View *v)
{
if (_keyboard_focus == v)
return false;
if (_keyboard_focus)
_keyboard_focus->set_focus(false);
_keyboard_focus = v;
_vstack->set_focused(v);
if (v)
v->set_focus(true);
return true;
}
int
User_state::get_input_stream_info_for_id(l4_umword_t id, Input_info *info) const
{
lua_State *l = _l;
int top = lua_gettop(l);
lua_getglobal(l, "input_source_info");
lua_pushinteger(l, id);
if (lua_pcall(l, 1, 2, 0))
{
fprintf(stderr, "ERROR: lua event handling returned: %s.\n", lua_tostring(l, -1));
lua_pop(l, 1);
return -L4_ENOSYS;
}
int r = lua_tointeger(l, -2);
if (r < 0)
{
lua_settop(l, top);
return r;
}
L4Re::Event_stream_info *i = 0;
swig_type_info *type = SWIG_TypeQuery(l, "L4Re::Event_stream_info *");
if (!type)
{
fprintf(stderr, "Ooops: did not find type 'L4Re::Event_stream_info'\n");
lua_settop(l, top);
return -L4_EINVAL;
}
if (!SWIG_IsOK(SWIG_ConvertPtr(l, -1, (void**)&i, type, 0)))
{
fprintf(stderr, "Ooops: expected 'L4Re::Event_stream_info' as arg 2\n");
lua_settop(l, top);
return -L4_EINVAL;
}
if (!i)
{
lua_settop(l, top);
return -L4_EINVAL;
}
*info = *i;
lua_settop(l, top);
return r;
}
int
User_state::get_input_axis_info(l4_umword_t id, unsigned naxes, unsigned const *axis,
Input_absinfo *info, unsigned char *ax_mode) const
{
lua_State *l = _l;
int top = lua_gettop(l);
lua_getglobal(l, "input_source_abs_info");
lua_pushinteger(l, id);
for (unsigned i = 0; i < naxes; ++i)
lua_pushinteger(l, axis[i]);
if (lua_pcall(l, 1 + naxes, 1 + naxes, 0))
{
fprintf(stderr, "ERROR: lua event handling returned: %s.\n", lua_tostring(l, -1));
lua_settop(l, top);
return -L4_ENOSYS;
}
int r = lua_tointeger(l, top + 1);
if (r < 0)
{
lua_settop(l, top);
return r;
}
for (unsigned i = 0; i < naxes; ++i)
{
int ndx = top + i + 2;
if (!lua_istable(l, ndx) && !lua_isuserdata(l, ndx))
{
fprintf(stderr, "ERROR: lua event handling returned: %s.\n", lua_tostring(l, top + 1));
lua_settop(l, top);
return -L4_EINVAL;
}
lua_getfield(l, ndx, "value");
info[i].value = lua_tointeger(l, -1);
lua_pop(l, 1);
lua_getfield(l, ndx, "min");
info[i].min = lua_tointeger(l, -1);
lua_pop(l, 1);
lua_getfield(l, ndx, "max");
info[i].max = lua_tointeger(l, -1);
lua_pop(l, 1);
lua_getfield(l, ndx, "fuzz");
info[i].fuzz = lua_tointeger(l, -1);
lua_pop(l, 1);
lua_getfield(l, ndx, "flat");
info[i].flat = lua_tointeger(l, -1);
lua_pop(l, 1);
lua_getfield(l, ndx, "resolution");
info[i].resolution = lua_tointeger(l, -1);
lua_pop(l, 1);
if (ax_mode)
{
lua_getfield(l, ndx, "mode");
ax_mode[i] = lua_tointeger(l, -1);
lua_pop(l, 1);
}
}
lua_settop(l, top);
return r;
}
}

View File

@@ -0,0 +1,418 @@
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
#include <l4/mag-gfx/clip_guard>
#include "view_stack"
#include "view"
#include "session"
#include <cstdio>
#include <cstring>
namespace Mag_server {
class Redraw_queue
{
public:
enum { Num_entries = 100 };
// merge all overlapping rects in the queue
void merge()
{
for (unsigned i = last; i > 0; --i)
for (unsigned j = 0; j < last; ++j)
{
if (i - 1 == j)
continue;
if ((_q[j] & _q[i - 1]).valid())
{
_q[j] = _q[j] | _q[i - 1];
for (unsigned m = 0; m < last - i; m++)
_q[i - 1 + m] = _q[i + m];
--last;
break;
}
}
}
void q(Rect const &r)
{
if (!r.valid())
return;
//printf("q[%d,%d - %d,%d]\n", r.x1(), r.y1(), r.x2(), r.y2());
for (unsigned i = 0; i < last; ++i)
{
if ((_q[i] & r).valid())
{
// merge with overlapping rect
_q[i] = _q[i] | r;
merge();
return;
}
}
if (last < Num_entries)
_q[last++] = r; // add new entry
else
{
// queue is full, just merge with the last entry
_q[last - 1] = _q[last - 1] | r;
merge();
}
}
void clear()
{ last = 0; }
typedef Rect const *iterator;
iterator begin() const { return _q; }
iterator end() const { return _q + last; }
private:
Rect _q[Num_entries];
unsigned last;
};
static Redraw_queue rdq;
View const *
View_stack::next_view(View const *_v, View const *bg) const
{
for (Const_view_iter v = _top.iter(_v); v != _top.end();)
{
++v;
if (v == _top.end())
return 0;
unsigned sf = 0;
if (v->session())
sf = v->session()->flags();
if (sf & Session::F_ignore)
continue;
if (!v->background())
return *v;
if (v == _top.iter(_background) || v == _top.iter(bg))
return *v;
if (!bg && (sf & Session::F_default_background))
return *v;
}
return 0;
}
Rect
View_stack::outline(View const *v) const
{
if (_mode.flat() || !v->need_frame())
return *v;
else
return v->grow(v->frame_width());
}
void
View_stack::viewport(View *v, Rect const &pos, bool) const
{
Rect old = outline(v);
/* take over new view parameters */
v->set_geometry(pos);
Rect compound = old | outline(v);
/* update labels (except when moving the mouse cursor) */
if (v != top())
place_labels(compound);
/* update area on screen */
rdq.q(compound);
// draw_recursive(top(), 0, /*redraw ? 0 : view->session(),*/ compound);
}
void
View_stack::draw_frame(View const *v) const
{
if (_mode.flat() || !v->need_frame() || !v->session())
return;
Rgb32::Color color = v->session()->color();
Rgb32::Color outline = v->focused() ? Rgb32::White : Rgb32::Black;
int w = v->frame_width() - 1;
_canvas->draw_rect(v->offset(-1 - w, -1 - w, 1 + w, 1 + w), outline);
_canvas->draw_rect(*v, color, -w);
}
static void
draw_string_outline(Canvas *c, Point const &pos, Font const *f, char const *txt)
{
for (int i = -1; i <= 1; ++i)
for (int k = -1; k <= 1; ++k)
if (i || k)
c->draw_string(pos + Point(i, k), f, Rgb32::Black, txt);
}
void
View_stack::draw_label(View const *v) const
{
if (_mode.flat() || !v->need_frame())
return;
char const *const sl = v->session()->label();
Point pos = v->label_pos() + Point(1, 1);
draw_string_outline(_canvas, pos, _label_font, sl);
_canvas->draw_string(pos, _label_font, Rgb32::White, sl);
char const *const vl = v->title();
if (!vl)
return;
pos = pos + Point(_label_font->str_w(sl) + View::Label_sep, 0);
draw_string_outline(_canvas, pos, _label_font, vl);
_canvas->draw_string(pos, _label_font, Rgb32::White, vl);
}
void
View_stack::set_focused(View *v)
{
_focused = v;
if (!v)
return;
// stack all 'above' tagged views of the focussed session
// to the top. We keep their respective order.
Session *s = v->session();
if (!s)
return;
View_iter top = _top.iter(_no_stay_top);
for (View_iter t = _top.begin(); t != _top.end(); ++t)
{
if (!t->above())
continue;
if (t->session() == s)
{
stack(*t, *top, true);
top = t;
}
}
// if the view is not a background than raise the view relative to
// all views of other sessions, but keep the stacking order within
// it's session
if (v->background())
return;
for (top = --_top.iter(v);
top != _top.iter(_no_stay_top) && top != _top.end() && top->session() != s;
--top)
;
if (top != --_top.iter(v))
stack(v, *top, true);
}
void
View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect) const
{ draw_recursive(v, dst, rect, current_background()); }
void
View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect,
View const *bg) const
{
Rect clipped;
/* find next view that intersects with the current clipping rectangle */
while (v && !(clipped = outline(v) & rect).valid())
v = next_view(v, bg);
if (!v)
return;
View const *n = next_view(v, bg);
Rect_tuple border;
if (v->transparent() && n)
{
draw_recursive(n, dst, rect, bg);
n = 0;
}
else
border = rect - clipped;
if (n && border.t().valid())
draw_recursive(n, dst, border.t(), bg);
if (n && border.l().valid())
draw_recursive(n, dst, border.l(), bg);
if (!dst || dst == v || v->transparent())
{
Clip_guard g(_canvas, clipped);
draw_frame(v);
v->draw(_canvas, this, _mode);
draw_label(v);
}
if (n && border.r().valid())
draw_recursive(n, dst, border.r(), bg);
if (n && border.b().valid())
draw_recursive(n, dst, border.b(), bg);
}
void
View_stack::refresh_view(View const *v, View const *dst, Rect const &rect) const
{
(void)dst;
Rect r = rect;
if (v)
r = r & outline(v);
rdq.q(r);
//draw_recursive(top(), dst, r);
}
void
View_stack::flush()
{
//static int cnt = 0;
for (Redraw_queue::iterator i = rdq.begin(); i != rdq.end(); ++i)
{
//printf("redraw[%d] %d,%d-%d,%d\n", cnt++, i->x1(), i->y1(), i->x2(), i->y2());
draw_recursive(top(), 0, *i);
if (_canvas_view)
_canvas_view->refresh(i->x1(), i->y1(), i->w(), i->h());
}
rdq.clear();
}
void
View_stack::stack(View *v, View *pivot, bool behind)
{
if (_top.in_list(v))
remove(v);
if (behind)
insert_after(v, pivot);
else
insert_before(v, pivot);
place_labels(*v);
refresh_view(v, 0, outline(v));
}
void
View_stack::push_bottom(View *v)
{
Session *s = v->session();
View *b = s ? s->background() : 0;
stack(v, (b && (b != v)) ? b : _background, false);
}
View *
View_stack::find(Point const &pos) const
{
View *bg = current_background();
View *n = next_view(top(), bg);
while (n && !n->contains(pos))
n = next_view(n, bg);
return n;
}
void
View_stack::optimize_label_rec(View *cv, View *lv, Rect const &rect, Rect *optimal,
View *bg) const
{
/* if label already fits in optimized rectangle, we are happy */
if (optimal->fits(lv->label_sz()))
return;
/* find next view that intersects with the rectangle or the target view */
Rect clipped;
while (cv && cv != lv && !(clipped = outline(cv) & rect).valid())
cv = next_view(cv, bg);
/* reached end of view stack */
if (!cv)
return;
if (cv != lv && next_view(cv, bg))
{
/* cut current view from rectangle and go into sub rectangles */
Rect r[4] =
{ Rect(rect.p1(), Point(rect.x2(), clipped.y1() - 1)),
Rect(rect.p1(), Point(clipped.x1() - 1, rect.y2())),
Rect(Point(clipped.x2() + 1, rect.y1()), rect.p2()),
Rect(Point(rect.x1(), clipped.y2() + 1), rect.p2()) };
for (int i = 0; i < 4; i++)
optimize_label_rec(next_view(cv, bg), lv, r[i], optimal, bg);
return;
}
/*
* Now, cv equals lv and we must decide how to configure the
* optimal rectangle.
*/
/* stop if label does not fit vertically */
if (rect.h() < lv->label_sz().h())
return;
/*
* If label fits completely within current rectangle, we are done.
* If label's width is not fully visible, choose the widest rectangle.
*/
if (rect.fits(lv->label_sz()) || (rect.w() > optimal->w()))
*optimal = rect;
}
void
View_stack::do_place_labels(Rect const &rect) const
{
View *bg = current_background();
View *start = next_view(*_top.begin(), bg);
/* ignore mouse cursor */
for (View *view = start; view && next_view(view); view = next_view(view, bg))
if ((*view & rect).valid())
{
Rect old(view->label_pos(), view->label_sz());
/* calculate best visible label position */
Rect rect = Rect(Point(0, 0), _canvas->size()) & *view;
Rect best;
optimize_label_rec(start, view, rect, &best, bg);
/*
* If label is not fully visible, we ensure to display the first
* (most important) part. Otherwise, we center the label horizontally.
*/
int x = best.x1();
if (best.fits(view->label_sz()))
x += (best.w() - view->label_sz().w()) / 2;
view->label_pos(Point(x, best.y1()));
/* refresh old and new label positions */
refresh_view(view, view, old);
Rect n = Rect(view->label_pos(), view->label_sz());
refresh_view(view, view, n);
}
}
}

View File

@@ -0,0 +1,42 @@
#! /usr/bin/perl -W
use strict;
my $if_lvl = 0;
my $cpp = 0;
my $ext_c = 0;
while (<>)
{
chomp;
if (/^#ifdef\s+__cplusplus\s*$/)
{
$if_lvl++;
$cpp = $if_lvl;
}
elsif (/^#if.*$/)
{
$if_lvl++;
}
elsif (/^#endif\s*$/)
{
$cpp = 0 if $cpp == $if_lvl;
$if_lvl--;
}
if ($ext_c && $cpp && $cpp == $if_lvl && /^}/)
{
$ext_c = 0;
print ("// removed: }\n");
}
elsif ($cpp && $cpp == $if_lvl && /^\s*extern\s+"C"\s+{/)
{
print ("// removed: extern \"C\" {\n");
$ext_c = 1;
}
else
{
print("$_\n");
}
}