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