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/protocols>
12 #include <l4/re/namespace>
13 #include <l4/re/event_enums.h>
14 #include <l4/cxx/ipc_server>
15 #include <l4/re/error_helper>
17 #include <l4/re/dataspace>
18 #include <l4/re/mem_alloc>
19 #include <l4/re/util/video/goos_svr>
20 #include <l4/re/util/event_svr>
21 #include <l4/re/util/icu_svr>
22 #include <l4/re/video/goos-sys.h>
23 #include <l4/re/video/goos>
24 #include <l4/re/console>
25 #include <l4/re/util/meta>
27 #include <l4/mag/server/plugin>
28 #include <l4/mag/server/object>
29 #include <l4/mag/server/session>
30 #include <l4/mag/server/user_state>
31 #include <l4/mag-gfx/clip_guard>
32 #include <l4/mag-gfx/texture>
33 #include <l4/mag-gfx/factory>
35 #include <l4/cxx/list>
36 #include <l4/cxx/auto_ptr>
44 namespace Mag_server { namespace {
46 using L4Re::Util::Auto_cap;
48 using Mag_gfx::Texture;
52 class Mag_client : public Object, private Plugin
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);
62 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
70 : public Session, public Object,
71 public L4Re::Util::Icu_cap_array_svr<Mag_goos>
74 typedef L4Re::Util::Icu_cap_array_svr<Mag_goos> Icu_svr;
76 Core_api const *_core;
77 L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap _ev_ds;
79 L4Re::Rm::Auto_region<void*> _ev_ds_m;
80 L4Re::Event_buffer _events;
82 typedef std::vector<cxx::Ref_ptr<Client_buffer> > Buffer_vector;
83 typedef std::vector<cxx::Auto_ptr<Client_view> > View_vector;
85 Buffer_vector _buffers;
88 int screen_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
89 int event_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
92 Mag_goos(Core_api const *core);
94 void put_event(L4Re::Event_buffer::Event const &ne, bool trigger);
95 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
97 L4::Cap<void> rcv_cap() const { return _core->rcv_cap(); }
101 static void set_default_background(Session *_s, Property_handler const *, cxx::String const &);
105 class Client_buffer : public cxx::Ref_obj
108 L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap _ds;
109 L4Re::Rm::Auto_region<void *> _texture_mem;
115 Client_buffer(Core_api const *core, unsigned long size);
117 L4::Cap<L4Re::Dataspace> ds_cap() const { return _ds.get(); }
118 void *local_addr() const { return _texture_mem.get(); }
119 unsigned long size() const { return _size; }
123 class Client_view : public View
126 Core_api const *_core;
127 cxx::Ref_ptr<Client_buffer> _buffer;
132 unsigned long _buf_offset;
136 register Texture *tmp = _front_txt;
137 asm volatile ("" : : : "memory");
138 _front_txt = _back_txt;
143 Client_view(Core_api const *core, Mag_goos *screen);
144 virtual ~Client_view();
146 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
147 void draw(Canvas *, View_stack const *, Mode) const;
148 void handle_event(L4Re::Event_buffer::Event const &e, Point const &mouse);
150 void get_info(L4Re::Video::View::Info *inf) const;
151 void set_info(L4Re::Video::View::Info const &inf,
152 cxx::Ref_ptr<Client_buffer> const &b);
154 Session *session() const { return _screen; }
157 Client_view::Client_view(Core_api const *core, Mag_goos *screen)
158 : View(Rect(), F_need_frame), _core(core), _buffer(0), _screen(screen),
161 Pixel_info const *pi = core->user_state()->vstack()->canvas()->type();
163 _front_txt = pi->factory->create_texture(Area(0,0), (void*)1);
164 _back_txt = pi->factory->create_texture(Area(0,0), (void*)1);
165 calc_label_sz(core->label_font());
168 Client_view::~Client_view()
170 if (_screen && _screen->background() == this)
172 // look for other background views below
173 View_stack *vs = _core->user_state()->vstack();
174 // We can either search below this view in the stack, or
175 // we can search from the top of the stack to find the uppermost
176 // view of our session that is tagged as background
177 View *v = vs->next_view(this); // search below this view
178 // View *v = vs->top(); // Search from the top of the stack
179 for (; v; v = vs->next_view(v))
180 if (v != this && v->session() == _screen && v->background())
182 _screen->background(v);
185 _core->user_state()->forget_view(this);
192 Client_view::get_info(L4Re::Video::View::Info *inf) const
194 using L4Re::Video::Color_component;
195 inf->flags = L4Re::Video::View::F_fully_dynamic;
196 // we do not support chaning the pixel format
197 inf->flags &= ~L4Re::Video::View::F_set_pixel;
199 inf->flags |= L4Re::Video::View::F_above;
205 inf->buffer_offset = _buf_offset;
207 Pixel_info const *pi = 0;
208 pi = _front_txt->type();
210 inf->bytes_per_line = pi->bytes_per_pixel() * _front_txt->size().w();
211 inf->pixel_info = *pi;
214 inf->buffer_index = _buffer->index;
216 inf->buffer_index = ~0;
221 Client_view::set_info(L4Re::Video::View::Info const &inf,
222 cxx::Ref_ptr<Client_buffer> const &b)
224 Pixel_info const *pi = _core->user_state()->vstack()->canvas()->type();
226 bool recalc_height = false;
227 _back_txt->size(_front_txt->size());
228 _back_txt->pixels(_front_txt->pixels());
230 if (inf.flags & L4Re::Video::View::F_set_flags)
231 set_above(inf.flags & L4Re::Video::View::F_above);
233 if (inf.flags & L4Re::Video::View::F_set_background)
235 _core->user_state()->vstack()->push_bottom(this);
237 _screen->background(this);
240 if (inf.has_set_bytes_per_line())
242 _back_txt->size(Area(inf.bytes_per_line / pi->bytes_per_pixel(), 0));
243 recalc_height = true;
246 if (inf.has_set_buffer())
248 _back_txt->pixels((char *)b->local_addr() + _buf_offset);
250 recalc_height = true;
255 _back_txt->size(Area(0, 0));
256 _back_txt->pixels((char *)0);
257 _front_txt->size(Area(0, 0));
258 _front_txt->pixels((char *)0);
261 if (inf.has_set_buffer_offset() && _buffer)
263 _back_txt->pixels((char *)_buffer->local_addr() + inf.buffer_offset);
264 _buf_offset = inf.buffer_offset;
265 recalc_height = true;
268 if (recalc_height && _buffer)
270 unsigned long w = _back_txt->size().w();
271 unsigned long bw = w * pi->bytes_per_pixel();
289 _back_txt->size(Area(w, h));
292 if (_back_txt->size() != _front_txt->size()
293 || _back_txt->pixels() != _front_txt->pixels())
296 if (inf.has_set_position())
297 _core->user_state()->vstack()->viewport(this, Rect(Point(inf.xpos,
298 inf.ypos), Area(inf.width, inf.height)), true);
302 Mag_goos::Mag_goos(Core_api const *core)
303 : Icu_svr(1, &_ev_irq), _core(core)
305 L4Re::Env const *e = L4Re::Env::env();
306 _ev_ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
308 chksys(e->mem_alloc()->alloc(L4_PAGESIZE, _ev_ds.get()));
309 chksys(e->rm()->attach(&_ev_ds_m, L4_PAGESIZE, L4Re::Rm::Search_addr, _ev_ds.get()));
311 _events = L4Re::Event_buffer(_ev_ds_m.get(), L4_PAGESIZE);
314 void Mag_client::start(Core_api *core)
317 core->registry()->register_obj(cxx::Ref_ptr<Mag_client>(this), "mag");
318 if (!obj_cap().is_valid())
319 printf("Service registration failed.\n");
321 printf("Plugin: Mag_client service started\n");
324 void Mag_goos::set_default_background(Session *_s, Property_handler const *, cxx::String const &)
326 Mag_goos *s = static_cast<Mag_goos *>(_s);
328 s->flags(F_default_background, 0);
332 Session::Property_handler const _opts[] =
333 { { "default-background", false, &Mag_goos::set_default_background },
334 { "dfl-bg", false, &Mag_goos::set_default_background },
340 Mag_client::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
347 case L4::Meta::Protocol:
348 return L4Re::Util::handle_meta_request<L4::Factory>(ios);
349 case L4::Factory::Protocol:
350 if (L4::kobject_typeid<L4Re::Console>()->
351 has_proto(L4::Ipc::read<L4::Factory::Proto>(ios)))
353 L4::Ipc::Istream_copy cp_is = ios;
355 cxx::Ref_ptr<Mag_goos> cf(new Mag_goos(_core));
356 _core->set_session_options(cf.get(), cp_is, _opts);
358 _core->register_session(cf.get());
359 _core->registry()->register_obj(cf);
360 cf->obj_cap()->dec_refcnt(1);
362 ios << L4::Ipc::Snd_fpage(cf->obj_cap(), L4_CAP_FPAGE_RWSD);
367 return -L4_EBADPROTO;
372 Mag_client::destroy()
377 Mag_goos::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
384 case L4::Meta::Protocol:
385 return L4Re::Util::handle_meta_request<L4Re::Console>(ios);
386 case L4Re::Protocol::Goos:
387 return screen_dispatch(obj, ios);
388 case L4Re::Protocol::Event:
389 return event_dispatch(obj, ios);
391 return Icu_svr::dispatch(obj, ios);
393 return -L4_EBADPROTO;
399 Mag_goos::event_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
405 case L4Re::Event_::Get:
406 ios << L4::Ipc::Snd_fpage(_ev_ds.get().fpage(L4_CAP_FPAGE_RW));
414 Mag_goos::screen_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
421 case ::L4Re::Video::Goos_::Info:
423 using L4Re::Video::Color_component;
424 using L4Re::Video::Goos;
427 Area a = _core->user_state()->vstack()->canvas()->size();
428 Pixel_info const *mag_pi = _core->user_state()->vstack()->canvas()->type();
431 i.flags = Goos::F_pointer
432 | Goos::F_dynamic_views
433 | Goos::F_dynamic_buffers;
435 i.num_static_views = 0;
436 i.num_static_buffers = 0;
437 i.pixel_info = *mag_pi;
444 case L4Re::Video::Goos_::Create_buffer:
449 cxx::Ref_ptr<Client_buffer> b(new Client_buffer(_core, size));
450 _buffers.push_back(b);
451 b->index = _buffers.size() - 1;
453 ios << L4::Ipc::Snd_fpage(b->ds_cap(), L4_CAP_FPAGE_RW);
458 case L4Re::Video::Goos_::Create_view:
460 cxx::Auto_ptr<Client_view> v(new Client_view(_core, this));
462 for (View_vector::iterator i = _views.begin(); i != _views.end();
471 return _views.size() - 1;
474 case L4Re::Video::Goos_::Delete_view:
478 if (idx >= _views.size())
481 _views[idx].reset(0);
485 case L4Re::Video::Goos_::Get_buffer:
489 if (idx >= _buffers.size())
492 ios << _buffers[idx]->ds_cap();
496 case L4Re::Video::Goos_::View_info:
500 if (idx >= _views.size())
503 Client_view *cv = _views[idx].get();
505 L4Re::Video::View::Info vi;
513 case L4Re::Video::Goos_::View_set_info:
517 if (idx >= _views.size())
520 Client_view *cv = _views[idx].get();
522 L4Re::Video::View::Info vi;
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);
538 case L4Re::Video::Goos_::View_stack:
540 Client_view *pivot = 0;
545 ios >> cvi >> pvi >> behind;
547 if (cvi >= _views.size())
550 cv = _views[cvi].get();
552 if (pvi < _views.size())
553 pivot = _views[pvi].get();
558 _core->user_state()->vstack()->push_bottom(cv);
560 _core->user_state()->vstack()->push_top(cv);
563 _core->user_state()->vstack()->stack(cv, pivot, behind);
568 case L4Re::Video::Goos_::View_refresh:
572 ios >> idx >> x >> y >> w >> h;
574 if (idx >= _views.size())
577 Client_view *cv = _views[idx].get();
578 _core->user_state()->vstack()->refresh_view(cv, 0, Rect(cv->p1() + Point(x,y), Area(w,h)));
583 case L4Re::Video::Goos_::Screen_refresh:
586 ios >> x >> y >> w >> h;
588 _core->user_state()->vstack()->refresh_view(0, 0, Rect(Point(x,y), Area(w,h)));
606 Client_buffer::Client_buffer(Core_api const *, unsigned long size)
607 : _size(l4_round_page(size))
609 L4Re::Rm::Auto_region<void *> dsa;
610 _ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
612 L4Re::chksys(L4Re::Env::env()->mem_alloc()->alloc(_size, _ds.get()));
613 L4Re::chksys(L4Re::Env::env()->rm()->attach(&dsa, _size,
614 L4Re::Rm::Search_addr, _ds.get()));
622 Mag_goos::put_event(L4Re::Event_buffer::Event const &ne, bool trigger)
624 if (_events.put(ne) && trigger)
630 Client_view::draw(Canvas *c, View_stack const *, Mode mode) const
632 Canvas::Mix_mode op = mode.flat() ? Canvas::Solid : Canvas::Mixed;
633 if (mode.xray() && !mode.kill() && focused())
636 Clip_guard cg(c, *this);
638 if (!c->clip_valid())
641 Rgb32::Color mix_color = /*mode.kill() ? kill_color() :*/ session()->color();
645 c->draw_texture(_front_txt, mix_color, p1(), op);
646 s = _front_txt->size();
651 c->draw_box(Rect(p1() + Point(0, s.h()), Area(size().w(), r.h())), mix_color);
653 if (r.w() > 0 && size().h() != r.h())
654 c->draw_box(Rect(p1() + Point(s.w(), 0), Area(r.w(), s.h())), mix_color);
658 Client_view::handle_event(L4Re::Event_buffer::Event const &e,
661 if (e.payload.type == L4RE_EV_MAX)
663 L4Re::Event_buffer::Event ne;
665 ne.payload.type = L4RE_EV_ABS;
666 ne.payload.code = L4RE_ABS_X;
667 ne.payload.value = mouse.x();
668 ne.payload.stream_id = e.payload.stream_id;
669 _screen->put_event(ne, false);
670 ne.payload.code = L4RE_ABS_Y;
671 ne.payload.value = mouse.y();
672 _screen->put_event(ne, true);
676 _screen->put_event(e, true);
681 static Mag_client _mag_client;