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
94 if (v->session() && v->session()->ignore())
100 if (v == _background || v == bg)
108 View_stack::outline(View const *v) const
110 if (_mode.flat() || !v->need_frame())
113 return v->grow(v->frame_width());
117 View_stack::viewport(View *v, Rect const &pos, bool) const
119 Rect old = outline(v);
121 /* take over new view parameters */
122 v->set_geometry(pos);
124 Rect compound = old | outline(v);
126 /* update labels (except when moving the mouse cursor) */
128 place_labels(compound);
130 /* update area on screen */
132 // draw_recursive(top(), 0, /*redraw ? 0 : view->session(),*/ compound);
136 View_stack::draw_frame(View const *v) const
138 if (_mode.flat() || !v->need_frame() || !v->session())
141 Rgb32::Color color = v->session()->color();
142 Rgb32::Color outline = v->focused() ? Rgb32::White : Rgb32::Black;
144 int w = v->frame_width()-1;
145 _canvas->draw_rect(v->offset(-1-w, -1-w, 1+w, 1+w), outline);
146 _canvas->draw_rect(*v, color, -w);
150 draw_string_outline(Canvas *c, Point const &pos, Font const *f, char const *txt)
152 for (int i = -1; i <= 1; ++i)
153 for (int k = -1; k <= 1; ++k)
155 c->draw_string(pos + Point(i, k), f, Rgb32::Black, txt);
159 View_stack::draw_label(View const *v) const
161 if (_mode.flat() || !v->need_frame())
164 char const *const sl = v->session()->label();
165 Point pos = v->label_pos() + Point(1, 1);
166 draw_string_outline(_canvas, pos, _label_font, sl);
167 _canvas->draw_string(pos, _label_font, Rgb32::White, sl);
169 char const *const vl = v->title();
173 pos = pos + Point(_label_font->str_w(sl) + View::Label_sep, 0);
174 draw_string_outline(_canvas, pos, _label_font, vl);
175 _canvas->draw_string(pos, _label_font, Rgb32::White, vl);
179 View_stack::set_focused(View *v)
185 // stack all 'above' tagged views of the focussed session
186 // to the top. We keep their respective order.
187 Session *s = v->session();
191 View *top = _no_stay_top;
192 for (View *t = _top.first(); t; t = _top.next(t))
197 if (t->session() == s)
204 // if the view is not a background than raise the view relative to
205 // all views of other sessions, but keep the stacking order within
210 for (top = _top.prev(v); top != _no_stay_top && top && top->session() != s;
211 top = _top.prev(top))
214 if (top != _top.prev(v))
219 View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect) const
220 { draw_recursive(v, dst, rect, current_background()); }
223 View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect,
224 View const *bg) const
228 /* find next view that intersects with the current clipping rectangle */
229 while (v && !(clipped = outline(v) & rect).valid())
230 v = next_view(v, bg);
235 View const *n = next_view(v, bg);
238 if (v->transparent() && n)
240 draw_recursive(n, dst, rect, bg);
244 border = rect - clipped;
246 if (n && border.t().valid())
247 draw_recursive(n, dst, border.t(), bg);
248 if (n && border.l().valid())
249 draw_recursive(n, dst, border.l(), bg);
251 if (!dst || dst == v || v->transparent())
253 Clip_guard g(_canvas, clipped);
255 v->draw(_canvas, this, _mode);
259 if (n && border.r().valid())
260 draw_recursive(n, dst, border.r(), bg);
261 if (n && border.b().valid())
262 draw_recursive(n, dst, border.b(), bg);
266 View_stack::refresh_view(View const *v, View const *dst, Rect const &rect) const
274 //draw_recursive(top(), dst, r);
280 //static int cnt = 0;
281 for (Redraw_queue::iterator i = rdq.begin(); i != rdq.end(); ++i)
283 //printf("redraw[%d] %d,%d-%d,%d\n", cnt++, i->x1(), i->y1(), i->x2(), i->y2());
284 draw_recursive(top(), 0, *i);
286 _canvas_view->refresh(i->x1(), i->y1(), i->w(), i->h());
293 View_stack::stack(View *v, View *pivot, bool behind)
297 insert_after(v, pivot);
299 insert_before(v, pivot);
303 refresh_view(v, 0, outline(v));
307 View_stack::push_bottom(View *v)
309 Session *s = v->session();
310 View *b = s ? s->background() : 0;
311 stack(v, (b && (b != v)) ? b : _background, false);
316 View_stack::find(Point const &pos) const
318 View *bg = current_background();
319 View *n = next_view(top(), bg);
320 while (n && !n->contains(pos))
321 n = next_view(n, bg);
327 View_stack::optimize_label_rec(View *cv, View *lv, Rect const &rect, Rect *optimal,
330 /* if label already fits in optimized rectangle, we are happy */
331 if (optimal->fits(lv->label_sz()))
334 /* find next view that intersects with the rectangle or the target view */
336 while (cv && cv != lv && !(clipped = outline(cv) & rect).valid())
337 cv = next_view(cv, bg);
339 /* reached end of view stack */
343 if (cv != lv && next_view(cv, bg))
345 /* cut current view from rectangle and go into sub rectangles */
347 { Rect(rect.p1(), Point(rect.x2(), clipped.y1() - 1)),
348 Rect(rect.p1(), Point(clipped.x1() - 1, rect.y2())),
349 Rect(Point(clipped.x2() + 1, rect.y1()), rect.p2()),
350 Rect(Point(rect.x1(), clipped.y2() + 1), rect.p2()) };
351 for (int i = 0; i < 4; i++)
352 optimize_label_rec(next_view(cv, bg), lv, r[i], optimal, bg);
358 * Now, cv equals lv and we must decide how to configure the
362 /* stop if label does not fit vertically */
363 if (rect.h() < lv->label_sz().h())
367 * If label fits completely within current rectangle, we are done.
368 * If label's width is not fully visible, choose the widest rectangle.
370 if (rect.fits(lv->label_sz()) || (rect.w() > optimal->w()))
375 View_stack::do_place_labels(Rect const &rect) const
377 View *bg = current_background();
378 View *start = next_view(_top.first(), bg);
379 /* ignore mouse cursor */
380 for (View *view = start; view && next_view(view); view = next_view(view, bg))
381 if ((*view & rect).valid())
383 Rect old(view->label_pos(), view->label_sz());
385 /* calculate best visible label position */
386 Rect rect = Rect(Point(0, 0), _canvas->size()) & *view;
388 optimize_label_rec(start, view, rect, &best, bg);
391 * If label is not fully visible, we ensure to display the first
392 * (most important) part. Otherwise, we center the label horizontally.
395 if (best.fits(view->label_sz()))
396 x += (best.w() - view->label_sz().w()) / 2;
398 view->label_pos(Point(x, best.y1()));
400 /* refresh old and new label positions */
401 refresh_view(view, view, old);
402 Rect n = Rect(view->label_pos(), view->label_sz());
403 refresh_view(view, view, n);