2 * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
11 #include <l4/re/namespace>
12 #include <l4/re/event_enums.h>
13 #include <l4/re/event-sys.h>
14 #include <l4/re/error_helper>
16 #include <l4/re/dataspace>
17 #include <l4/re/util/video/goos_svr>
18 #include <l4/re/util/event_svr>
19 #include <l4/re/util/icu_svr>
20 #include <l4/re/video/goos-sys.h>
21 #include <l4/re/video/goos>
22 #include <l4/re/console>
23 #include <l4/re/util/meta>
25 #include <l4/mag/server/plugin>
26 #include <l4/mag/server/object>
27 #include <l4/mag/server/session>
28 #include <l4/mag/server/user_state>
29 #include <l4/mag-gfx/clip_guard>
30 #include <l4/mag-gfx/texture>
31 #include <l4/mag-gfx/factory>
33 #include <l4/cxx/list>
34 #include <l4/cxx/auto_ptr>
42 namespace Mag_server { namespace {
44 using L4Re::Util::Auto_cap;
46 using Mag_gfx::Texture;
51 public L4::Epiface_t<Mag_client, L4::Factory, Object>,
55 Core_api const *_core;
58 Mag_client() : Plugin("Mag client") {}
59 char const *type() const { return "Mag client"; }
60 void start(Core_api *core);
63 long op_create(L4::Factory::Rights rights, L4::Ipc::Cap<void> &obj,
64 l4_mword_t proto, L4::Ipc::Varg_list<> const &args);
72 public L4::Epiface_t<Mag_goos, L4Re::Console, Object>,
73 public L4Re::Util::Icu_cap_array_svr<Mag_goos>
76 typedef L4Re::Util::Icu_cap_array_svr<Mag_goos> Icu_svr;
77 typedef L4Re::Video::Goos::Rights Goos_rights;
79 Core_api const *_core;
80 L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap _ev_ds;
82 L4Re::Rm::Auto_region<void*> _ev_ds_m;
83 L4Re::Event_buffer _events;
85 typedef std::vector<cxx::Ref_ptr<Client_buffer> > Buffer_vector;
86 typedef std::vector<cxx::Auto_ptr<Client_view> > View_vector;
88 Buffer_vector _buffers;
92 long op_info(Goos_rights, L4Re::Video::Goos::Info &i);
94 long op_get_static_buffer(Goos_rights, unsigned idx,
95 L4::Ipc::Cap<L4Re::Dataspace> &ds);
97 long op_create_buffer(Goos_rights, unsigned long, L4::Ipc::Cap<L4Re::Dataspace> &);
99 long op_delete_buffer(Goos_rights, unsigned)
100 { return -L4_ENOSYS; }
102 long op_create_view(Goos_rights);
104 long op_delete_view(Goos_rights, unsigned);
106 long op_view_info(Goos_rights, unsigned idx, L4Re::Video::View::Info &info);
108 long op_set_view_info(Goos_rights, unsigned, L4Re::Video::View::Info const &);
110 long op_view_stack(Goos_rights, unsigned view, unsigned pivot, bool behind);
112 long op_view_refresh(Goos_rights, unsigned idx, int x, int y, int w, int h);
114 long op_refresh(Goos_rights, int x, int y, int w, int h);
116 long op_get_buffer(L4Re::Event::Rights, L4::Ipc::Cap<L4Re::Dataspace> &ds)
119 ds = L4::Ipc::Cap<L4Re::Dataspace>(_ev_ds.get(), L4_CAP_FPAGE_RW);
123 long op_get_num_streams(L4Re::Event::Rights)
124 { return -L4_ENOSYS; }
126 long op_get_stream_info(L4Re::Event::Rights, int, L4Re::Event_stream_info &)
127 { return -L4_ENOSYS; }
129 long op_get_stream_info_for_id(L4Re::Event::Rights, l4_umword_t id,
130 L4Re::Event_stream_info &info)
131 { return _core->user_state()->get_input_stream_info_for_id(id, &info); }
133 long op_get_axis_info(L4Re::Event::Rights, l4_umword_t id,
134 L4::Ipc::Array_in_buf<unsigned, unsigned long> const &axes,
135 L4::Ipc::Array_ref<L4Re::Event_absinfo, unsigned long> &info)
137 unsigned naxes = cxx::min<unsigned>(L4RE_ABS_MAX, axes.length);
141 L4Re::Event_absinfo _info[naxes];
142 int r = _core->user_state()->get_input_axis_info(id, naxes, axes.data, _info, 0);
146 for (unsigned i = 0; i < naxes; ++i)
147 info.data[i] = _info[i];
153 long op_get_stream_state_for_id(L4Re::Event::Rights, l4_umword_t,
154 L4Re::Event_stream_state &)
155 { return -L4_ENOSYS; }
160 Mag_goos(Core_api const *core);
162 using Icu_svr::op_info;
164 void put_event(Hid_report *e, bool trigger);
165 void put_event(l4_umword_t stream, int type, int code, int value,
170 static void set_default_background(Session *_s, Property_handler const *, cxx::String const &);
173 class Client_buffer : public cxx::Ref_obj
176 L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap _ds;
177 L4Re::Rm::Auto_region<void *> _texture_mem;
183 Client_buffer(Core_api const *core, unsigned long size);
185 L4::Cap<L4Re::Dataspace> ds_cap() const { return _ds.get(); }
186 void *local_addr() const { return _texture_mem.get(); }
187 unsigned long size() const { return _size; }
191 class Client_view : public View
194 Core_api const *_core;
195 cxx::Ref_ptr<Client_buffer> _buffer;
200 unsigned long _buf_offset;
204 Texture *tmp = _front_txt;
205 asm volatile ("" : : : "memory");
206 _front_txt = _back_txt;
211 Client_view(Core_api const *core, Mag_goos *screen);
212 virtual ~Client_view();
214 void draw(Canvas *, View_stack const *, Mode) const;
215 void handle_event(Hid_report *e, Point const &mouse, bool core_dev);
217 void get_info(L4Re::Video::View::Info *inf) const;
218 void set_info(L4Re::Video::View::Info const &inf,
219 cxx::Ref_ptr<Client_buffer> const &b);
221 Session *session() const { return _screen; }
224 Client_view::Client_view(Core_api const *core, Mag_goos *screen)
225 : View(Rect(), F_need_frame), _core(core), _buffer(0), _screen(screen),
228 Pixel_info const *pi = core->user_state()->vstack()->canvas()->type();
230 _front_txt = pi->factory->create_texture(Area(0,0), (void*)1);
231 _back_txt = pi->factory->create_texture(Area(0,0), (void*)1);
232 calc_label_sz(core->label_font());
235 Client_view::~Client_view()
237 if (_screen && _screen->background() == this)
239 // look for other background views below
240 View_stack *vs = _core->user_state()->vstack();
241 // We can either search below this view in the stack, or
242 // we can search from the top of the stack to find the uppermost
243 // view of our session that is tagged as background
244 View *v = vs->next_view(this); // search below this view
245 // View *v = vs->top(); // Search from the top of the stack
246 for (; v; v = vs->next_view(v))
247 if (v != this && v->session() == _screen && v->background())
249 _screen->background(v);
252 _core->user_state()->forget_view(this);
259 Client_view::get_info(L4Re::Video::View::Info *inf) const
261 using L4Re::Video::Color_component;
262 inf->flags = L4Re::Video::View::F_fully_dynamic;
263 // we do not support changing the pixel format
264 inf->flags &= ~L4Re::Video::View::F_set_pixel;
266 inf->flags |= L4Re::Video::View::F_above;
272 inf->buffer_offset = _buf_offset;
274 Pixel_info const *pi = 0;
275 pi = _front_txt->type();
277 inf->bytes_per_line = pi->bytes_per_pixel() * _front_txt->size().w();
278 inf->pixel_info = *pi;
281 inf->buffer_index = _buffer->index;
283 inf->buffer_index = ~0;
288 Client_view::set_info(L4Re::Video::View::Info const &inf,
289 cxx::Ref_ptr<Client_buffer> const &b)
291 Pixel_info const *pi = _core->user_state()->vstack()->canvas()->type();
293 bool recalc_height = false;
294 _back_txt->size(_front_txt->size());
295 _back_txt->pixels(_front_txt->pixels());
297 if (inf.flags & L4Re::Video::View::F_set_flags)
298 set_above(inf.flags & L4Re::Video::View::F_above);
300 if (inf.flags & L4Re::Video::View::F_set_background)
302 _core->user_state()->vstack()->push_bottom(this);
304 _screen->background(this);
307 if (inf.has_set_bytes_per_line())
309 _back_txt->size(Area(inf.bytes_per_line / pi->bytes_per_pixel(), 0));
310 recalc_height = true;
313 if (inf.has_set_buffer())
315 _back_txt->pixels((char *)b->local_addr() + _buf_offset);
317 recalc_height = true;
322 _back_txt->size(Area(0, 0));
323 _back_txt->pixels((char *)0);
324 _front_txt->size(Area(0, 0));
325 _front_txt->pixels((char *)0);
328 if (inf.has_set_buffer_offset() && _buffer)
330 _back_txt->pixels((char *)_buffer->local_addr() + inf.buffer_offset);
331 _buf_offset = inf.buffer_offset;
332 recalc_height = true;
335 if (recalc_height && _buffer)
337 unsigned long w = _back_txt->size().w();
338 unsigned long bw = w * pi->bytes_per_pixel();
356 _back_txt->size(Area(w, h));
359 if (_back_txt->size() != _front_txt->size()
360 || _back_txt->pixels() != _front_txt->pixels())
363 if (inf.has_set_position())
364 _core->user_state()->vstack()->viewport(this, Rect(Point(inf.xpos,
365 inf.ypos), Area(inf.width, inf.height)), true);
369 Mag_goos::Mag_goos(Core_api const *core)
370 : Icu_svr(1, &_ev_irq), _core(core)
372 L4Re::Env const *e = L4Re::Env::env();
373 _ev_ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
375 chksys(e->mem_alloc()->alloc(L4_PAGESIZE, _ev_ds.get()));
376 chksys(e->rm()->attach(&_ev_ds_m, L4_PAGESIZE, L4Re::Rm::Search_addr,
377 L4::Ipc::make_cap_rw(_ev_ds.get())));
379 _events = L4Re::Event_buffer(_ev_ds_m.get(), L4_PAGESIZE);
382 void Mag_client::start(Core_api *core)
385 core->registry()->register_obj(cxx::Ref_ptr<Mag_client>(this), "mag");
386 if (!obj_cap().is_valid())
387 printf("Service registration failed.\n");
389 printf("Plugin: Mag_client service started\n");
392 void Mag_goos::set_default_background(Session *_s, Property_handler const *, cxx::String const &)
394 Mag_goos *s = static_cast<Mag_goos *>(_s);
396 s->flags(F_default_background, 0);
400 Session::Property_handler const _opts[] =
401 { { "default-background", false, &Mag_goos::set_default_background },
402 { "dfl-bg", false, &Mag_goos::set_default_background },
408 Mag_client::op_create(L4::Factory::Rights, L4::Ipc::Cap<void> &obj,
409 l4_mword_t proto, L4::Ipc::Varg_list<> const &args)
411 if (!L4::kobject_typeid<L4Re::Console>()->has_proto(proto))
414 cxx::Ref_ptr<Mag_goos> cf(new Mag_goos(_core));
415 _core->set_session_options(cf.get(), args, _opts);
417 _core->register_session(cf.get());
418 _core->registry()->register_obj(cf);
419 cf->obj_cap()->dec_refcnt(1);
421 obj = L4::Ipc::make_cap(cf->obj_cap(), L4_CAP_FPAGE_RWSD);
427 Mag_client::destroy()
432 Mag_goos::op_info(Goos_rights, L4Re::Video::Goos::Info &i)
434 using L4Re::Video::Color_component;
435 using L4Re::Video::Goos;
437 Area a = _core->user_state()->vstack()->canvas()->size();
438 Pixel_info const *mag_pi = _core->user_state()->vstack()->canvas()->type();
441 i.flags = Goos::F_pointer
442 | Goos::F_dynamic_views
443 | Goos::F_dynamic_buffers;
445 i.num_static_views = 0;
446 i.num_static_buffers = 0;
447 i.pixel_info = *mag_pi;
453 Mag_goos::op_create_buffer(Goos_rights, unsigned long size,
454 L4::Ipc::Cap<L4Re::Dataspace> &ds)
456 cxx::Ref_ptr<Client_buffer> b(new Client_buffer(_core, size));
457 _buffers.push_back(b);
458 b->index = _buffers.size() - 1;
459 ds = L4::Ipc::Cap<L4Re::Dataspace>(b->ds_cap(), L4_CAP_FPAGE_RW);
464 Mag_goos::op_create_view(Goos_rights)
466 cxx::Auto_ptr<Client_view> v(new Client_view(_core, this));
468 for (View_vector::iterator i = _views.begin(); i != _views.end();
477 return _views.size() - 1;
481 Mag_goos::op_delete_view(Goos_rights, unsigned idx)
483 if (idx >= _views.size())
486 _views[idx].reset(0);
491 Mag_goos::op_get_static_buffer(Goos_rights, unsigned idx,
492 L4::Ipc::Cap<L4Re::Dataspace> &ds)
494 if (idx >= _buffers.size())
497 ds = L4::Ipc::Cap<L4Re::Dataspace>(_buffers[idx]->ds_cap(), L4_CAP_FPAGE_RW);
502 Mag_goos::op_view_info(Goos_rights, unsigned idx, L4Re::Video::View::Info &info)
504 if (idx >= _views.size())
507 Client_view *cv = _views[idx].get();
509 L4Re::Video::View::Info vi;
517 Mag_goos::op_set_view_info(Goos_rights, unsigned idx,
518 L4Re::Video::View::Info const &vi)
520 if (idx >= _views.size())
523 Client_view *cv = _views[idx].get();
525 cxx::Weak_ptr<Client_buffer> cb(0);
526 if (vi.has_set_buffer())
528 if (vi.buffer_index >= _buffers.size())
531 cb = _buffers[vi.buffer_index];
534 cv->set_info(vi, cb);
539 Mag_goos::op_view_stack(Goos_rights, unsigned cvi, unsigned pvi, bool behind)
541 Client_view *pivot = 0;
544 if (cvi >= _views.size())
547 cv = _views[cvi].get();
549 if (pvi < _views.size())
550 pivot = _views[pvi].get();
555 _core->user_state()->vstack()->push_bottom(cv);
557 _core->user_state()->vstack()->push_top(cv);
560 _core->user_state()->vstack()->stack(cv, pivot, behind);
566 Mag_goos::op_view_refresh(Goos_rights, unsigned idx, int x, int y, int w, int h)
568 if (idx >= _views.size())
571 Client_view *cv = _views[idx].get();
572 _core->user_state()->vstack()->refresh_view(cv, 0, Rect(cv->p1() + Point(x,y), Area(w,h)));
578 Mag_goos::op_refresh(Goos_rights, int x, int y, int w, int h)
580 _core->user_state()->vstack()->refresh_view(0, 0, Rect(Point(x,y), Area(w,h)));
593 Client_buffer::Client_buffer(Core_api const *, unsigned long size)
594 : _size(l4_round_page(size))
596 L4Re::Rm::Auto_region<void *> dsa;
597 _ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
599 L4Re::chksys(L4Re::Env::env()->mem_alloc()->alloc(_size, _ds.get()));
600 L4Re::chksys(L4Re::Env::env()->rm()
601 ->attach(&dsa, _size, L4Re::Rm::Search_addr,
602 L4::Ipc::make_cap_rw(_ds.get())));
609 Mag_goos::put_event(Hid_report *e, bool _trigger)
611 if (post_hid_report(e, _events, Axis_xfrm_noop()) && _trigger)
616 Mag_goos::put_event(l4_umword_t stream, int type, int code, int value,
619 L4Re::Event_buffer::Event e;
621 e.payload.stream_id = stream;
622 e.payload.type = type;
623 e.payload.code = code;
624 e.payload.value = value;
631 Client_view::draw(Canvas *c, View_stack const *, Mode mode) const
633 Canvas::Mix_mode op = mode.flat() ? Canvas::Solid : Canvas::Mixed;
634 if (mode.xray() && !mode.kill() && focused())
637 Clip_guard cg(c, *this);
639 if (!c->clip_valid())
642 Rgb32::Color mix_color = /*mode.kill() ? kill_color() :*/ session()->color();
646 c->draw_texture(_front_txt, mix_color, p1(), op);
647 s = _front_txt->size();
652 c->draw_box(Rect(p1() + Point(0, s.h()), Area(size().w(), r.h())), mix_color);
654 if (r.w() > 0 && size().h() != r.h())
655 c->draw_box(Rect(p1() + Point(s.w(), 0), Area(r.w(), s.h())), mix_color);
659 Client_view::handle_event(Hid_report *e, Point const &, bool)
661 _screen->put_event(e, true);
665 static Mag_client _mag_client;