]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/mag/plugins/mag_client/mag_client.cc
update
[l4.git] / l4 / pkg / mag / plugins / mag_client / mag_client.cc
1 /*
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)
5  *
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.
9  */
10 #include <l4/re/env>
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>
16 #include <l4/re/rm>
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>
26
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>
34
35 #include <l4/cxx/list>
36 #include <l4/cxx/auto_ptr>
37
38 #include <cstring>
39 #include <cstdio>
40 #include <memory>
41 #include <vector>
42 #include <list>
43
44 namespace Mag_server { namespace {
45
46 using L4Re::Util::Auto_cap;
47 using std::auto_ptr;
48 using Mag_gfx::Texture;
49 using Mag_gfx::Area;
50 using L4Re::chksys;
51
52 class Mag_client : public Object, private Plugin
53 {
54 private:
55   Core_api const *_core;
56
57 public:
58   Mag_client() : Plugin("Mag client") {}
59   char const *type() const { return "Mag client"; }
60   void start(Core_api *core);
61
62   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
63   void destroy();
64 };
65
66 class Client_buffer;
67 class Client_view;
68
69 class Mag_goos
70 : public Session, public Object,
71   public L4Re::Util::Icu_cap_array_svr<Mag_goos>
72 {
73 private:
74   typedef L4Re::Util::Icu_cap_array_svr<Mag_goos> Icu_svr;
75
76   Core_api const *_core;
77   L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap _ev_ds;
78   Irq _ev_irq;
79   L4Re::Rm::Auto_region<void*> _ev_ds_m;
80   L4Re::Event_buffer _events;
81
82   typedef std::vector<cxx::Ref_ptr<Client_buffer> >  Buffer_vector;
83   typedef std::vector<cxx::Auto_ptr<Client_view> > View_vector;
84
85   Buffer_vector _buffers;
86   View_vector _views;
87
88   int screen_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
89   int event_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
90
91 public:
92   Mag_goos(Core_api const *core);
93
94   void put_event(L4Re::Event_buffer::Event const &ne, bool trigger);
95   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
96
97   L4::Cap<void> rcv_cap() const { return _core->rcv_cap(); }
98
99   void destroy();
100 };
101
102
103 class Client_buffer : public cxx::Ref_obj
104 {
105 private:
106   L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap _ds;
107   L4Re::Rm::Auto_region<void *> _texture_mem;
108   unsigned long _size;
109
110 public:
111   unsigned index;
112
113   Client_buffer(Core_api const *core, unsigned long size);
114
115   L4::Cap<L4Re::Dataspace> ds_cap() const { return _ds.get(); }
116   void *local_addr() const { return _texture_mem.get(); }
117   unsigned long size() const { return _size; }
118 };
119
120
121 class Client_view : public View
122 {
123 private:
124   Core_api const *_core;
125   cxx::Ref_ptr<Client_buffer> _buffer;
126   Mag_goos *_screen;
127   Texture *_front_txt;
128   Texture *_back_txt;
129
130   unsigned long _buf_offset;
131
132   void swap_textures()
133   {
134     register Texture *tmp = _front_txt;
135     asm volatile ("" : : : "memory");
136     _front_txt = _back_txt;
137     _back_txt = tmp;
138   }
139
140 public:
141   Client_view(Core_api const *core, Mag_goos *screen);
142   virtual ~Client_view();
143
144   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
145   void draw(Canvas *, View_stack const *, Mode) const;
146   void handle_event(L4Re::Event_buffer::Event const &e, Point const &mouse);
147
148   void get_info(L4Re::Video::View::Info *inf) const;
149   void set_info(L4Re::Video::View::Info const &inf,
150                 cxx::Ref_ptr<Client_buffer> const &b);
151
152   Session *session() const { return _screen; }
153 };
154
155 Client_view::Client_view(Core_api const *core, Mag_goos *screen)
156 : View(Rect(), F_need_frame), _core(core), _buffer(0), _screen(screen),
157   _buf_offset(0)
158 {
159   Pixel_info const *pi = core->user_state()->vstack()->canvas()->type();
160
161   _front_txt = pi->factory->create_texture(Area(0,0), (void*)1);
162   _back_txt = pi->factory->create_texture(Area(0,0), (void*)1);
163   calc_label_sz(core->label_font());
164 }
165
166 Client_view::~Client_view()
167 {
168   if (_screen && _screen->background() == this)
169     {
170       // look for other background views below
171       View_stack *vs = _core->user_state()->vstack();
172       // We can either search below this view in the stack, or
173       // we can search from the top of the stack to find the uppermost
174       // view of our session that is tagged as background
175       View *v = vs->next_view(this); // search below this view
176       // View *v = vs->top(); // Search from the top of the stack
177       for (; v; v = vs->next_view(v))
178         if (v != this && v->session() == _screen && v->background())
179           break;
180       _screen->background(v);
181     }
182
183   _core->user_state()->forget_view(this);
184   delete _back_txt;
185   delete _front_txt;
186 }
187
188 inline
189 void
190 Client_view::get_info(L4Re::Video::View::Info *inf) const
191 {
192   using L4Re::Video::Color_component;
193   inf->flags = L4Re::Video::View::F_fully_dynamic;
194   // we do not support chaning the pixel format
195   inf->flags &= ~L4Re::Video::View::F_set_pixel;
196   if (above())
197     inf->flags |= L4Re::Video::View::F_above;
198
199   inf->xpos = x1();
200   inf->ypos = y1();
201   inf->width = w();
202   inf->height = h();
203   inf->buffer_offset = _buf_offset;
204
205   Pixel_info const *pi = 0;
206   pi = _front_txt->type();
207
208   inf->bytes_per_line = pi->bytes_per_pixel() * _front_txt->size().w();
209   inf->pixel_info = *pi;
210
211   if (_buffer)
212     inf->buffer_index = _buffer->index;
213   else
214     inf->buffer_index = ~0;
215 }
216
217 inline
218 void
219 Client_view::set_info(L4Re::Video::View::Info const &inf,
220                       cxx::Ref_ptr<Client_buffer> const &b)
221 {
222   Pixel_info const *pi = _core->user_state()->vstack()->canvas()->type();
223
224   bool recalc_height = false;
225   _back_txt->size(_front_txt->size());
226   _back_txt->pixels(_front_txt->pixels());
227
228   if (inf.flags & L4Re::Video::View::F_set_flags)
229     set_above(inf.flags & L4Re::Video::View::F_above);
230
231   if (inf.flags & L4Re::Video::View::F_set_background)
232     {
233       _core->user_state()->vstack()->push_bottom(this);
234       set_as_background();
235       _screen->background(this);
236     }
237
238   if (inf.has_set_bytes_per_line())
239     {
240       _back_txt->size(Area(inf.bytes_per_line / pi->bytes_per_pixel(), 0));
241       recalc_height = true;
242     }
243
244   if (inf.has_set_buffer())
245     {
246       _back_txt->pixels((char *)b->local_addr() + _buf_offset);
247       _buffer = b;
248       recalc_height = true;
249     }
250
251   if (!_buffer)
252     {
253       _back_txt->size(Area(0, 0));
254       _back_txt->pixels((char *)0);
255       _front_txt->size(Area(0, 0));
256       _front_txt->pixels((char *)0);
257     }
258
259   if (inf.has_set_buffer_offset() && _buffer)
260     {
261       _back_txt->pixels((char *)_buffer->local_addr() + inf.buffer_offset);
262       _buf_offset = inf.buffer_offset;
263       recalc_height = true;
264     }
265
266   if (recalc_height && _buffer)
267     {
268       unsigned long w = _back_txt->size().w();
269       unsigned long bw = w * pi->bytes_per_pixel();
270       unsigned long h;
271
272       if (bw > 0 && w > 0)
273         {
274           h = _buffer->size();
275           if (h > _buf_offset)
276             h -= _buf_offset;
277           else
278             h = 0;
279
280           h /= bw;
281         }
282       else
283         {
284           w = 0;
285           h = 0;
286         }
287       _back_txt->size(Area(w, h));
288     }
289
290   if (_back_txt->size() != _front_txt->size()
291       || _back_txt->pixels() != _front_txt->pixels())
292     swap_textures();
293
294   if (inf.has_set_position())
295     _core->user_state()->vstack()->viewport(this, Rect(Point(inf.xpos,
296             inf.ypos), Area(inf.width, inf.height)), true);
297 }
298
299
300 Mag_goos::Mag_goos(Core_api const *core)
301 : Icu_svr(1, &_ev_irq), _core(core)
302 {
303   L4Re::Env const *e = L4Re::Env::env();
304   _ev_ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
305
306   chksys(e->mem_alloc()->alloc(L4_PAGESIZE, _ev_ds.get()));
307   chksys(e->rm()->attach(&_ev_ds_m, L4_PAGESIZE, L4Re::Rm::Search_addr, _ev_ds.get()));
308
309   _events = L4Re::Event_buffer(_ev_ds_m.get(), L4_PAGESIZE);
310 }
311
312 void Mag_client::start(Core_api *core)
313 {
314   _core = core;
315   core->registry()->register_obj(cxx::Ref_ptr<Mag_client>(this), "mag");
316   if (!obj_cap().is_valid())
317     printf("Service registration failed.\n");
318   else
319     printf("Plugin: Mag_client service started\n");
320 }
321
322 int
323 Mag_client::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
324 {
325   l4_msgtag_t tag;
326   ios >> tag;
327
328   switch (tag.label())
329     {
330     case L4::Meta::Protocol:
331       return L4Re::Util::handle_meta_request<L4::Factory>(ios);
332     case L4::Factory::Protocol:
333       if (L4::kobject_typeid<L4Re::Console>()->
334             has_proto(L4::Ipc::read<L4::Factory::Proto>(ios)))
335         {
336           L4::Ipc::Istream_copy cp_is = ios;
337           
338           cxx::Ref_ptr<Mag_goos> cf(new Mag_goos(_core));
339           _core->set_session_options(cf.get(), cp_is);
340
341           _core->register_session(cf.get());
342           _core->registry()->register_obj(cf);
343           cf->obj_cap()->dec_refcnt(1);
344
345           ios <<  L4::Ipc::Snd_fpage(cf->obj_cap(), L4_CAP_FPAGE_RWSD);
346           return L4_EOK;
347         }
348       return -L4_ENODEV;
349     default:
350       return -L4_EBADPROTO;
351     }
352 }
353
354 void
355 Mag_client::destroy()
356 {
357 }
358
359 int
360 Mag_goos::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
361 {
362   l4_msgtag_t tag;
363   ios >> tag;
364
365   switch (tag.label())
366     {
367     case L4::Meta::Protocol:
368       return L4Re::Util::handle_meta_request<L4Re::Console>(ios);
369     case L4Re::Protocol::Goos:
370       return screen_dispatch(obj, ios);
371     case L4Re::Protocol::Event:
372       return event_dispatch(obj, ios);
373     case L4_PROTO_IRQ:
374       return Icu_svr::dispatch(obj, ios);
375     default:
376       return -L4_EBADPROTO;
377     }
378 }
379
380
381 int
382 Mag_goos::event_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
383 {
384   L4::Opcode op;
385   ios >> op;
386   switch (op)
387     {
388     case L4Re::Event_::Get:
389       ios << L4::Ipc::Snd_fpage(_ev_ds.get().fpage(L4_CAP_FPAGE_RW));
390       return L4_EOK;
391     default:
392       return -L4_ENOSYS;
393     }
394 }
395
396 int
397 Mag_goos::screen_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
398 {
399   L4::Opcode op;
400   ios >> op;
401
402   switch (op)
403     {
404     case ::L4Re::Video::Goos_::Info:
405         {
406           using L4Re::Video::Color_component;
407           using L4Re::Video::Goos;
408
409           Goos::Info i;
410           Area a = _core->user_state()->vstack()->canvas()->size();
411           Pixel_info const *mag_pi = _core->user_state()->vstack()->canvas()->type();
412           i.width = a.w();
413           i.height = a.h();
414           i.flags = Goos::F_pointer
415             | Goos::F_dynamic_views
416             | Goos::F_dynamic_buffers;
417
418           i.num_static_views = 0;
419           i.num_static_buffers = 0;
420           i.pixel_info = *mag_pi;
421
422           ios.put(i);
423
424           return L4_EOK;
425         }
426
427     case L4Re::Video::Goos_::Create_buffer:
428         {
429           unsigned long size;
430           ios >> size;
431
432           cxx::Ref_ptr<Client_buffer> b(new Client_buffer(_core, size));
433           _buffers.push_back(b);
434           b->index = _buffers.size() - 1;
435
436           ios << L4::Ipc::Snd_fpage(b->ds_cap(), L4_CAP_FPAGE_RW);
437
438           return b->index;
439         }
440
441     case L4Re::Video::Goos_::Create_view:
442         {
443           cxx::Auto_ptr<Client_view> v(new Client_view(_core, this));
444           unsigned idx = 0;
445           for (View_vector::iterator i = _views.begin(); i != _views.end();
446                ++i, ++idx)
447             if (!*i)
448               {
449                 *i = v;
450                 return idx;
451               }
452
453           _views.push_back(v);
454           return _views.size() - 1;
455         }
456
457     case L4Re::Video::Goos_::Delete_view:
458         {
459           unsigned idx;
460           ios >> idx;
461           if (idx >= _views.size())
462             return -L4_ERANGE;
463
464           _views[idx].reset(0);
465           return 0;
466         }
467
468     case L4Re::Video::Goos_::Get_buffer:
469         {
470           unsigned idx;
471           ios >> idx;
472           if (idx >= _buffers.size())
473             return -L4_ERANGE;
474
475           ios << _buffers[idx]->ds_cap();
476           return L4_EOK;
477         }
478
479     case L4Re::Video::Goos_::View_info:
480         {
481           unsigned idx;
482           ios >> idx;
483           if (idx >= _views.size())
484             return -L4_ERANGE;
485
486           Client_view *cv = _views[idx].get();
487
488           L4Re::Video::View::Info vi;
489           vi.view_index = idx;
490           cv->get_info(&vi);
491           ios.put(vi);
492
493           return L4_EOK;
494         }
495
496     case L4Re::Video::Goos_::View_set_info:
497         {
498           unsigned idx;
499           ios >> idx;
500           if (idx >= _views.size())
501             return -L4_ERANGE;
502
503           Client_view *cv = _views[idx].get();
504
505           L4Re::Video::View::Info vi;
506           ios.get(vi);
507
508           cxx::Weak_ptr<Client_buffer> cb(0);
509           if (vi.has_set_buffer())
510             {
511               if (vi.buffer_index >= _buffers.size())
512                 return -L4_ERANGE;
513
514               cb = _buffers[vi.buffer_index];
515             }
516
517           cv->set_info(vi, cb);
518           return L4_EOK;
519         }
520
521     case L4Re::Video::Goos_::View_stack:
522         {
523           Client_view *pivot = 0;
524           Client_view *cv;
525           bool behind;
526           unsigned cvi, pvi;
527
528           ios >> cvi >> pvi >> behind;
529
530           if (cvi >= _views.size())
531             return -L4_ERANGE;
532
533           cv = _views[cvi].get();
534
535           if (pvi < _views.size())
536             pivot = _views[pvi].get();
537
538           if (!pivot)
539             {
540               if (!behind)
541                 _core->user_state()->vstack()->push_bottom(cv);
542               else
543                 _core->user_state()->vstack()->push_top(cv);
544             }
545           else
546             _core->user_state()->vstack()->stack(cv, pivot, behind);
547
548         }
549       return L4_EOK;
550
551     case L4Re::Video::Goos_::View_refresh:
552         {
553           unsigned idx;
554           int x, y, w, h;
555           ios >> idx >> x >> y >> w >> h;
556
557           if (idx >= _views.size())
558             return -L4_ERANGE;
559
560           Client_view *cv = _views[idx].get();
561           _core->user_state()->vstack()->refresh_view(cv, 0, Rect(cv->p1() + Point(x,y), Area(w,h)));
562
563           return L4_EOK;
564         }
565
566     case L4Re::Video::Goos_::Screen_refresh:
567         {
568           int x, y, w, h;
569           ios >> x >> y >> w >> h;
570
571           _core->user_state()->vstack()->refresh_view(0, 0, Rect(Point(x,y), Area(w,h)));
572
573           return L4_EOK;
574         }
575
576     default:
577       return -L4_ENOSYS;
578     }
579 }
580
581 void
582 Mag_goos::destroy()
583 {
584   _buffers.clear();
585   _views.clear();
586 }
587
588
589 Client_buffer::Client_buffer(Core_api const *, unsigned long size)
590 : _size(l4_round_page(size))
591 {
592   L4Re::Rm::Auto_region<void *> dsa;
593   _ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
594
595   L4Re::chksys(L4Re::Env::env()->mem_alloc()->alloc(_size, _ds.get()));
596   L4Re::chksys(L4Re::Env::env()->rm()->attach(&dsa, _size,
597         L4Re::Rm::Search_addr, _ds.get()));
598
599   _texture_mem = dsa;
600 }
601
602
603
604 void
605 Mag_goos::put_event(L4Re::Event_buffer::Event const &ne, bool trigger)
606 {
607   if (_events.put(ne) && trigger)
608     _ev_irq.trigger();
609 }
610
611
612 void
613 Client_view::draw(Canvas *c, View_stack const *, Mode mode) const
614 {
615   Canvas::Mix_mode op = mode.flat() ? Canvas::Solid : Canvas::Mixed;
616   Rgb32::Color frame_color = focused() ? Rgb32::White : View::frame_color();
617   if (mode.xray() && !mode.kill() && focused())
618     op = Canvas::Solid;
619
620   Clip_guard cg(c, *this);
621
622   if (!c->clip_valid())
623     return;
624
625   Rgb32::Color mix_color = /*mode.kill() ? kill_color() :*/ session()->color();
626   Area s(0, 0);
627   if (_buffer)
628     {
629       c->draw_texture(_front_txt, mix_color, p1(), op);
630       s = _front_txt->size();
631     }
632
633   Area r = size() - s;
634   if (r.h() > 0)
635     c->draw_box(Rect(p1() + Point(0, s.h()), Area(size().w(), r.h())), mix_color);
636
637   if (r.w() > 0 && size().h() != r.h())
638     c->draw_box(Rect(p1() + Point(s.w(), 0), Area(r.w(), s.h())), mix_color);
639 }
640
641 void
642 Client_view::handle_event(L4Re::Event_buffer::Event const &e,
643                           Point const &mouse)
644 {
645   if (e.payload.type == L4RE_EV_MAX)
646     {
647       L4Re::Event_buffer::Event ne;
648       ne.time = e.time;
649       ne.payload.type = L4RE_EV_ABS;
650       ne.payload.code = L4RE_ABS_X;
651       ne.payload.value = mouse.x();
652       ne.payload.stream_id = e.payload.stream_id;
653       _screen->put_event(ne, false);
654       ne.payload.code = L4RE_ABS_Y;
655       ne.payload.value = mouse.y();
656       _screen->put_event(ne, true);
657       return;
658     }
659
660   _screen->put_event(e, true);
661
662 }
663
664
665 static Mag_client _mag_client;
666
667 }}