]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/mag/plugins/client_fb/client_fb.cc
update
[l4.git] / l4 / pkg / mag / plugins / client_fb / client_fb.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 "client_fb.h"
11
12 #include <l4/mag-gfx/clip_guard>
13 #include <l4/mag-gfx/texture>
14
15 #include <l4/mag/server/view_stack>
16 #include <l4/mag/server/factory>
17
18 #include <l4/re/env>
19 #include <l4/re/event_enums.h>
20 #include <l4/re/error_helper>
21 #include <l4/re/util/cap_alloc>
22 #include <l4/sys/factory>
23 #include <l4/re/util/meta>
24 #include <l4/re/console>
25
26 #include <l4/mag/server/user_state>
27 #include <cstdio>
28 #include <cstring>
29
30
31 namespace Mag_server {
32
33 using L4Re::chksys;
34 using L4Re::chkcap;
35 using L4Re::Util::Auto_cap;
36
37 enum { Bar_height = 16 };
38
39 Client_fb::Client_fb(Core_api const *core)
40 : View(Rect(), F_need_frame),
41   Icu_svr(1, &_ev_irq),
42   _core(core), _fb(0),
43   _bar_height(Bar_height),
44   _flags(0)
45 {}
46
47 void
48 Client_fb::set_geometry_prop(Session *_s, Property_handler const *, cxx::String const &v)
49 {
50   Client_fb *s = static_cast<Client_fb*>(_s);
51   // ignore multiple geometry properties
52   if (s->_fb)
53     return;
54
55   int w, h, x=50, y=50;
56   int r;
57
58   cxx::String a = v;
59
60   r = a.from_dec(&w);
61   if (r >= a.len() || a[r] != 'x')
62     L4Re::chksys(-L4_EINVAL, "invalid geometry format");
63
64   a = a.substr(r + 1);
65   r = a.from_dec(&h);
66
67   if (r < a.len() && a[r] == '+')
68     {
69       a = a.substr(r + 1);
70       r = a.from_dec(&x);
71     }
72
73   if (r < a.len() && a[r] == '+')
74     {
75       a = a.substr(r + 1);
76       r = a.from_dec(&y);
77     }
78
79   if (w <= 0 || h <= 0 || w >= 10000 || h >= 10000)
80     L4Re::chksys(-L4_ERANGE, "invalid geometry (too big)");
81
82   Area sz = s->_core->user_state()->vstack()->canvas()->size();
83
84   if (x < 10 - w)
85     x = 10 - w;
86
87   if (x >= sz.w())
88     x = sz.w() - 10;
89
90   if (y < 10 - h)
91     y = 10 - h;
92
93   if (y >= sz.h())
94     y = sz.h() - 10;
95
96   s->set_geometry(Rect(Point(x, y), Area(w, h)));
97 }
98
99 void
100 Client_fb::set_flags_prop(Session *_s, Property_handler const *p, cxx::String const &)
101 {
102   Client_fb *s = static_cast<Client_fb*>(_s);
103
104   if (!strcmp(p->tag, "focus"))
105     s->_flags |= F_fb_focus;
106
107   if (!strcmp(p->tag, "shaded"))
108     s->_flags |= F_fb_shaded;
109
110   if (!strcmp(p->tag, "fixed"))
111     s->_flags |= F_fb_fixed_location;
112 }
113
114 void
115 Client_fb::set_bar_height_prop(Session *_s, Property_handler const *, cxx::String const &v)
116 {
117   Client_fb *s = static_cast<Client_fb*>(_s);
118   int r = v.from_dec(&s->_bar_height);
119   if (r < v.len())
120     L4Re::chksys(-L4_EINVAL, "invalid bar height format");
121
122   s->_bar_height = std::max(std::min(s->_bar_height, 100), 4);
123 }
124
125 int
126 Client_fb::setup()
127 {
128   using L4Re::Video::View;
129   using L4Re::Video::Color_component;
130   using L4Re::Video::Goos;
131
132   Area res(size());
133
134   Auto_cap<L4Re::Dataspace>::Cap ds(
135       L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>());
136
137   Screen_factory *sf = dynamic_cast<Screen_factory*>(_core->user_state()->vstack()->canvas()->type()->factory);
138   //Screen_factory *sf = dynamic_cast<Screen_factory*>(Rgb16::type()->factory);
139
140   L4Re::chksys(L4Re::Env::env()->mem_alloc()->alloc(sf->get_texture_size(res),
141                                                     ds.get()));
142
143   L4Re::Rm::Auto_region<void *> dsa;
144   L4Re::chksys(L4Re::Env::env()->rm()->attach(&dsa, ds->size(), L4Re::Rm::Search_addr, ds.get(), 0, L4_SUPERPAGESHIFT));
145
146   _fb = sf->create_texture(res, dsa.get());
147
148   set_geometry(Rect(p1(), visible_size()));
149   dsa.release();
150   _fb_ds = ds.release();
151
152   if (_flags & F_fb_focus)
153     _core->user_state()->set_focus(this);
154
155   _view_info.flags = View::F_none;
156
157   _view_info.view_index = 0;
158   _view_info.xpos = 0;
159   _view_info.ypos = 0;
160   _view_info.width = _fb->size().w();
161   _view_info.height = _fb->size().h();
162   _view_info.buffer_offset = 0;
163   _view_info.buffer_index = 0;
164   _view_info.bytes_per_line = _view_info.width * _fb->type()->bytes_per_pixel();
165   _view_info.pixel_info = *_fb->type();
166
167   _screen_info.flags = Goos::F_pointer;
168   _screen_info.width = _view_info.width;
169   _screen_info.height = _view_info.height;
170   _screen_info.num_static_views = 1;
171   _screen_info.num_static_buffers = 1;
172   _screen_info.pixel_info = _view_info.pixel_info;
173
174
175   L4Re::Env const *e = L4Re::Env::env();
176   _ev_ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
177
178
179   chksys(e->mem_alloc()->alloc(L4_PAGESIZE, _ev_ds.get()));
180   chksys(e->rm()->attach(&_ev_ds_m, L4_PAGESIZE, L4Re::Rm::Search_addr, _ev_ds.get(), 0, L4_PAGESHIFT));
181
182   _events = L4Re::Event_buffer(_ev_ds_m.get(), L4_PAGESIZE);
183
184   calc_label_sz(_core->label_font());
185   return 0;
186 }
187
188 void
189 Client_fb::draw(Canvas *canvas, View_stack const *, Mode mode) const
190 {
191   /* use dimming in x-ray mode */
192   Canvas::Mix_mode op = mode.flat() ? Canvas::Solid : Canvas::Mixed;
193
194   /* is this the currently focused view? */
195   Rgb32::Color frame_color = focused() ? Rgb32::White : View::frame_color();
196
197   /* do not dim the focused view in x-ray mode */
198   if (mode.xray() && !mode.kill() && focused())
199     op = Canvas::Solid;
200
201   /*
202    * The view content and label should never overdraw the
203    * frame of the view in non-flat Nitpicker modes. The frame
204    * is located outside the view area. By shrinking the
205    * clipping area to the view area, we protect the frame.
206    */
207   Clip_guard clip_guard(canvas, *this);
208
209   /*
210    * If the clipping area shrinked to zero,
211    * we do not process drawing operations.
212    */
213   if (!canvas->clip_valid()/* || !_session*/)
214     return;
215
216   /* draw view content */
217   Rgb32::Color mix_color = /*mode.kill() ? kill_color() :*/ session()->color();
218
219   canvas->draw_box(top(_bar_height), Rgb32::Color(56, 68, 88));
220
221   canvas->draw_texture(_fb, mix_color, p1() + Point(0, _bar_height), op);
222 }
223
224 Area
225 Client_fb::visible_size() const
226 {
227   if (_flags & F_fb_shaded)
228     return Area(_fb->size().w(), _bar_height);
229
230   return _fb->size() + Area(0, _bar_height);
231 }
232
233
234 void
235 Client_fb::toggle_shaded()
236 {
237   Rect r = *this;
238   _flags ^= F_fb_shaded;
239   Rect n = Rect(p1(), visible_size());
240   set_geometry(n);
241   _core->user_state()->vstack()->refresh_view(0, 0, r | n);
242 }
243
244 void
245 Client_fb::handle_event(L4Re::Event_buffer::Event const &e,
246                         Point const &mouse)
247 {
248   static Point left_drag;
249
250   if (e.payload.type == L4RE_EV_ABS && e.payload.code == 1 && left_drag != Point())
251     {
252       Rect npos = Rect(p1() + mouse - left_drag, size());
253       left_drag = mouse;
254       _core->user_state()->vstack()->viewport(this, npos, true);
255       return;
256     }
257
258   Rect bar = top(_bar_height);
259
260   if (e.payload.type == L4RE_EV_KEY)
261     {
262       View_stack *_stack = _core->user_state()->vstack();
263       if (e.payload.code == L4RE_BTN_LEFT && e.payload.value == 1 &&
264           !_stack->on_top(this))
265         _stack->push_top(this);
266
267       if (e.payload.code == L4RE_BTN_LEFT
268           && bar.contains(mouse)
269           && !(_flags & F_fb_fixed_location))
270         {
271           if (e.payload.value == 1)
272             left_drag = mouse;
273           else if (e.payload.value == 0)
274             left_drag = Point();
275           return;
276         }
277
278       if (e.payload.code == L4RE_BTN_MIDDLE
279           && bar.contains(mouse)
280           && e.payload.value == 1)
281         {
282           toggle_shaded();
283           return;
284         }
285     }
286
287   if (e.payload.type == L4RE_EV_ABS && e.payload.code <= L4RE_ABS_Y)
288     {
289       // wait for the following ABS_Y axis
290       if (e.payload.type == L4RE_ABS_X)
291         return;
292
293       Rect r = (*this - bar).b();
294       if (!r.contains(mouse))
295         return;
296
297       Point mp = p1() + Point(0, _bar_height);
298       mp = Point(_fb->size()).min(Point(0,0).max(mouse - mp));
299       L4Re::Event_buffer::Event ne;
300       ne.time = e.time;
301       ne.payload.type = L4RE_EV_ABS;
302       ne.payload.code = L4RE_ABS_X;
303       ne.payload.value = mp.x();
304       ne.payload.stream_id = e.payload.stream_id;
305       _events.put(ne);
306       ne.payload.code = L4RE_ABS_Y;
307       ne.payload.value = mp.y();
308       _events.put(ne);
309       _ev_irq.trigger();
310       return;
311     }
312
313   // no events if window is shaded
314   if (_flags & F_fb_shaded)
315     return;
316
317   if (_events.put(e))
318     _ev_irq.trigger();
319
320 }
321
322
323 int
324 Client_fb::refresh(int x, int y, int w, int h)
325 {
326   _core->user_state()->vstack()->refresh_view(this, 0, Rect(p1() + Point(x, y + _bar_height), Area(w, h)));
327   return 0;
328 }
329
330 int
331 Client_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &s)
332 {
333   l4_msgtag_t tag;
334   s >> tag;
335
336   switch (tag.label())
337     {
338     case L4::Meta::Protocol:
339       return L4Re::Util::handle_meta_request<L4Re::Console>(s);
340     case L4_PROTO_IRQ:
341       return Icu_svr::dispatch(obj, s);
342     case L4Re::Protocol::Goos:
343       return L4Re::Util::Video::Goos_svr::dispatch(obj, s);
344     case L4Re::Protocol::Event:
345         {
346           L4::Opcode op;
347           s >> op;
348           switch (op)
349             {
350             case L4Re::Event_::Get:
351               s << _ev_ds.get();
352               return L4_EOK;
353             default:
354               return -L4_ENOSYS;
355             }
356         }
357     default:
358       return -L4_EBADPROTO;
359     }
360 }
361
362
363 void
364 Client_fb::destroy()
365 {
366   _core->user_state()->forget_view(this);
367   delete _fb;
368   _fb = 0;
369 }
370
371 }