2 * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
3 * economic rights: Technische Universität Dresden (Germany)
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU General Public License 2.
7 * Please see the COPYING-GPL-2 file for details.
9 #include <l4/mag-gfx/clip_guard>
18 namespace Mag_server {
23 enum { Num_entries = 100 };
25 // merge all overlapping rects in the queue
28 for (unsigned i = last; i > 0; --i)
29 for (unsigned j = 0; j < last; ++j)
34 if ((_q[j] & _q[i-1]).valid())
36 _q[j] = _q[j] | _q[i-1];
37 memmove(_q + i - 1, _q + i, (last - i) * sizeof(Rect));
48 //printf("q[%d,%d - %d,%d]\n", r.x1(), r.y1(), r.x2(), r.y2());
49 for (unsigned i = 0; i < last; ++i)
51 if ((_q[i] & r).valid())
53 // merge with overlapping rect
60 if (last < Num_entries)
61 _q[last++] = r; // add new entry
64 // queue is full, just merge with the last entry
65 _q[last-1] = _q[last - 1] | r;
73 typedef Rect const *iterator;
75 iterator begin() const { return _q; }
76 iterator end() const { return _q + last; }
83 static Redraw_queue rdq;
86 View_stack::next_view(View const *v, View const *bg) const
96 sf = v->session()->flags();
98 if (sf & Session::F_ignore)
101 if (!v->background())
104 if (v == _background || v == bg)
107 if (!bg && (sf & Session::F_default_background))
115 View_stack::outline(View const *v) const
117 if (_mode.flat() || !v->need_frame())
120 return v->grow(v->frame_width());
124 View_stack::viewport(View *v, Rect const &pos, bool) const
126 Rect old = outline(v);
128 /* take over new view parameters */
129 v->set_geometry(pos);
131 Rect compound = old | outline(v);
133 /* update labels (except when moving the mouse cursor) */
135 place_labels(compound);
137 /* update area on screen */
139 // draw_recursive(top(), 0, /*redraw ? 0 : view->session(),*/ compound);
143 View_stack::draw_frame(View const *v) const
145 if (_mode.flat() || !v->need_frame() || !v->session())
148 Rgb32::Color color = v->session()->color();
149 Rgb32::Color outline = v->focused() ? Rgb32::White : Rgb32::Black;
151 int w = v->frame_width()-1;
152 _canvas->draw_rect(v->offset(-1-w, -1-w, 1+w, 1+w), outline);
153 _canvas->draw_rect(*v, color, -w);
157 draw_string_outline(Canvas *c, Point const &pos, Font const *f, char const *txt)
159 for (int i = -1; i <= 1; ++i)
160 for (int k = -1; k <= 1; ++k)
162 c->draw_string(pos + Point(i, k), f, Rgb32::Black, txt);
166 View_stack::draw_label(View const *v) const
168 if (_mode.flat() || !v->need_frame())
171 char const *const sl = v->session()->label();
172 Point pos = v->label_pos() + Point(1, 1);
173 draw_string_outline(_canvas, pos, _label_font, sl);
174 _canvas->draw_string(pos, _label_font, Rgb32::White, sl);
176 char const *const vl = v->title();
180 pos = pos + Point(_label_font->str_w(sl) + View::Label_sep, 0);
181 draw_string_outline(_canvas, pos, _label_font, vl);
182 _canvas->draw_string(pos, _label_font, Rgb32::White, vl);
186 View_stack::set_focused(View *v)
192 // stack all 'above' tagged views of the focussed session
193 // to the top. We keep their respective order.
194 Session *s = v->session();
198 View *top = _no_stay_top;
199 for (View *t = _top.first(); t; t = _top.next(t))
204 if (t->session() == s)
211 // if the view is not a background than raise the view relative to
212 // all views of other sessions, but keep the stacking order within
217 for (top = _top.prev(v); top != _no_stay_top && top && top->session() != s;
218 top = _top.prev(top))
221 if (top != _top.prev(v))
226 View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect) const
227 { draw_recursive(v, dst, rect, current_background()); }
230 View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect,
231 View const *bg) const
235 /* find next view that intersects with the current clipping rectangle */
236 while (v && !(clipped = outline(v) & rect).valid())
237 v = next_view(v, bg);
242 View const *n = next_view(v, bg);
245 if (v->transparent() && n)
247 draw_recursive(n, dst, rect, bg);
251 border = rect - clipped;
253 if (n && border.t().valid())
254 draw_recursive(n, dst, border.t(), bg);
255 if (n && border.l().valid())
256 draw_recursive(n, dst, border.l(), bg);
258 if (!dst || dst == v || v->transparent())
260 Clip_guard g(_canvas, clipped);
262 v->draw(_canvas, this, _mode);
266 if (n && border.r().valid())
267 draw_recursive(n, dst, border.r(), bg);
268 if (n && border.b().valid())
269 draw_recursive(n, dst, border.b(), bg);
273 View_stack::refresh_view(View const *v, View const *dst, Rect const &rect) const
281 //draw_recursive(top(), dst, r);
287 //static int cnt = 0;
288 for (Redraw_queue::iterator i = rdq.begin(); i != rdq.end(); ++i)
290 //printf("redraw[%d] %d,%d-%d,%d\n", cnt++, i->x1(), i->y1(), i->x2(), i->y2());
291 draw_recursive(top(), 0, *i);
293 _canvas_view->refresh(i->x1(), i->y1(), i->w(), i->h());
300 View_stack::stack(View *v, View *pivot, bool behind)
304 insert_after(v, pivot);
306 insert_before(v, pivot);
310 refresh_view(v, 0, outline(v));
314 View_stack::push_bottom(View *v)
316 Session *s = v->session();
317 View *b = s ? s->background() : 0;
318 stack(v, (b && (b != v)) ? b : _background, false);
323 View_stack::find(Point const &pos) const
325 View *bg = current_background();
326 View *n = next_view(top(), bg);
327 while (n && !n->contains(pos))
328 n = next_view(n, bg);
334 View_stack::optimize_label_rec(View *cv, View *lv, Rect const &rect, Rect *optimal,
337 /* if label already fits in optimized rectangle, we are happy */
338 if (optimal->fits(lv->label_sz()))
341 /* find next view that intersects with the rectangle or the target view */
343 while (cv && cv != lv && !(clipped = outline(cv) & rect).valid())
344 cv = next_view(cv, bg);
346 /* reached end of view stack */
350 if (cv != lv && next_view(cv, bg))
352 /* cut current view from rectangle and go into sub rectangles */
354 { Rect(rect.p1(), Point(rect.x2(), clipped.y1() - 1)),
355 Rect(rect.p1(), Point(clipped.x1() - 1, rect.y2())),
356 Rect(Point(clipped.x2() + 1, rect.y1()), rect.p2()),
357 Rect(Point(rect.x1(), clipped.y2() + 1), rect.p2()) };
358 for (int i = 0; i < 4; i++)
359 optimize_label_rec(next_view(cv, bg), lv, r[i], optimal, bg);
365 * Now, cv equals lv and we must decide how to configure the
369 /* stop if label does not fit vertically */
370 if (rect.h() < lv->label_sz().h())
374 * If label fits completely within current rectangle, we are done.
375 * If label's width is not fully visible, choose the widest rectangle.
377 if (rect.fits(lv->label_sz()) || (rect.w() > optimal->w()))
382 View_stack::do_place_labels(Rect const &rect) const
384 View *bg = current_background();
385 View *start = next_view(_top.first(), bg);
386 /* ignore mouse cursor */
387 for (View *view = start; view && next_view(view); view = next_view(view, bg))
388 if ((*view & rect).valid())
390 Rect old(view->label_pos(), view->label_sz());
392 /* calculate best visible label position */
393 Rect rect = Rect(Point(0, 0), _canvas->size()) & *view;
395 optimize_label_rec(start, view, rect, &best, bg);
398 * If label is not fully visible, we ensure to display the first
399 * (most important) part. Otherwise, we center the label horizontally.
402 if (best.fits(view->label_sz()))
403 x += (best.w() - view->label_sz().w()) / 2;
405 view->label_pos(Point(x, best.y1()));
407 /* refresh old and new label positions */
408 refresh_view(view, view, old);
409 Rect n = Rect(view->label_pos(), view->label_sz());
410 refresh_view(view, view, n);