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

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);
}
}
}