X-Git-Url: https://rtime.felk.cvut.cz/gitweb/l4.git/blobdiff_plain/5a0e6ead0fbfbb912cd817abad695c078e82481c..8d9e85aaae867f39cdd610261e3a4181c25add2d:/l4/pkg/mag/server/src/view_stack.cc diff --git a/l4/pkg/mag/server/src/view_stack.cc b/l4/pkg/mag/server/src/view_stack.cc index 3d0d2ffb1..77d794284 100644 --- a/l4/pkg/mag/server/src/view_stack.cc +++ b/l4/pkg/mag/server/src/view_stack.cc @@ -10,6 +10,7 @@ #include "view_stack" #include "view" +#include "session" #include #include @@ -81,13 +82,35 @@ private: static Redraw_queue rdq; +View const * +View_stack::next_view(View const *v, View const *bg) const +{ + while (v) + { + v = _top.next(v); + if (!v) + return 0; + + if (v->session() && v->session()->ignore()) + continue; + + if (!v->background()) + return v; + + if (v == _background || v == bg) + return v; + } + + return 0; +} + Rect View_stack::outline(View const *v) const { if (_mode.flat() || !v->need_frame()) return *v; else - return v->grow(3); + return v->grow(v->frame_width()); } void @@ -100,11 +123,9 @@ View_stack::viewport(View *v, Rect const &pos, bool) const Rect compound = old | outline(v); -#if 0 /* update labels (except when moving the mouse cursor) */ if (v != top()) - _place_labels(compound); -#endif + place_labels(compound); /* update area on screen */ rdq.q(compound); @@ -114,13 +135,24 @@ View_stack::viewport(View *v, Rect const &pos, bool) const void View_stack::draw_frame(View const *v) const { - if (_mode.flat() || !v->need_frame()) + if (_mode.flat() || !v->need_frame() || !v->session()) return; - Rgb32::Color color = v->focused() ? Rgb32::White : View::frame_color(); - _canvas->draw_rect(v->offset(-3, -3, 3, 3), Rgb32::Black); - _canvas->draw_rect(v->offset(-2, -2, 2, 2), color); - _canvas->draw_rect(v->offset(-1, -1, 1, 1), Rgb32::Black); + Rgb32::Color color = v->session()->color(); + Rgb32::Color outline = v->focused() ? Rgb32::White : Rgb32::Black; + + int w = v->frame_width()-1; + _canvas->draw_rect(v->offset(-1-w, -1-w, 1+w, 1+w), outline); + _canvas->draw_rect(*v, color, -w); +} + +static void +draw_string_outline(Canvas *c, Point const &pos, Font const *f, char const *txt) +{ + for (int i = -1; i <= 1; ++i) + for (int k = -1; k <= 1; ++k) + if (i || k) + c->draw_string(pos + Point(i, k), f, Rgb32::Black, txt); } void @@ -128,27 +160,93 @@ View_stack::draw_label(View const *v) const { if (_mode.flat() || !v->need_frame()) return; + + char const *const sl = v->session()->label(); + Point pos = v->label_pos() + Point(1, 1); + draw_string_outline(_canvas, pos, _label_font, sl); + _canvas->draw_string(pos, _label_font, Rgb32::White, sl); + + char const *const vl = v->title(); + if (!vl) + return; + + pos = pos + Point(_label_font->str_w(sl) + View::Label_sep, 0); + draw_string_outline(_canvas, pos, _label_font, vl); + _canvas->draw_string(pos, _label_font, Rgb32::White, vl); +} + +void +View_stack::set_focused(View *v) +{ + _focused = v; + if (!v) + return; + + // stack all 'above' tagged views of the focussed session + // to the top. We keep their respective order. + Session *s = v->session(); + if (!s) + return; + + View *top = _no_stay_top; + for (View *t = _top.first(); t; t = _top.next(t)) + { + if (!t->above()) + continue; + + if (t->session() == s) + { + stack(t, top, true); + top = t; + } + } + + // if the view is not a background than raise the view relative to + // all views of other sessions, but keep the stacking order within + // it's session + if (v->background()) + return; + + for (top = _top.prev(v); top != _no_stay_top && top && top->session() != s; + top = _top.prev(top)) + ; + + if (top != _top.prev(v)) + stack(v, top, true); } void View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect) const +{ draw_recursive(v, dst, rect, current_background()); } + +void +View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect, + View const *bg) const { Rect clipped; /* find next view that intersects with the current clipping rectangle */ - for ( ; v && !(clipped = outline(v) & rect).valid(); ) - v = v->next(); + while (v && !(clipped = outline(v) & rect).valid()) + v = next_view(v, bg); if (!v) return; - Rect_tuple border = rect - clipped; + View const *n = next_view(v, bg); + Rect_tuple border; - View const *n = v->next(); - if (n && border.t.valid()) - draw_recursive(n, dst, border.t); - if (n && border.l.valid()) - draw_recursive(n, dst, border.l); + if (v->transparent() && n) + { + draw_recursive(n, dst, rect, bg); + n = 0; + } + else + border = rect - clipped; + + if (n && border.t().valid()) + draw_recursive(n, dst, border.t(), bg); + if (n && border.l().valid()) + draw_recursive(n, dst, border.l(), bg); if (!dst || dst == v || v->transparent()) { @@ -158,10 +256,10 @@ View_stack::draw_recursive(View const *v, View const *dst, Rect const &rect) con draw_label(v); } - if (n && border.r.valid()) - draw_recursive(n, dst, border.r); - if (n && border.b.valid()) - draw_recursive(n, dst, border.b); + if (n && border.r().valid()) + draw_recursive(n, dst, border.r(), bg); + if (n && border.b().valid()) + draw_recursive(n, dst, border.b(), bg); } void @@ -179,8 +277,10 @@ View_stack::refresh_view(View const *v, View const *dst, Rect const &rect) const void View_stack::flush() { + //static int cnt = 0; for (Redraw_queue::iterator i = rdq.begin(); i != rdq.end(); ++i) { + //printf("redraw[%d] %d,%d-%d,%d\n", cnt++, i->x1(), i->y1(), i->x2(), i->y2()); draw_recursive(top(), 0, *i); if (_canvas_view) _canvas_view->refresh(i->x1(), i->y1(), i->w(), i->h()); @@ -198,18 +298,110 @@ View_stack::stack(View *v, View *pivot, bool behind) else insert_before(v, pivot); + place_labels(*v); + refresh_view(v, 0, outline(v)); } +void +View_stack::push_bottom(View *v) +{ + Session *s = v->session(); + View *b = s ? s->background() : 0; + stack(v, (b && (b != v)) ? b : _background, false); +} + View * View_stack::find(Point const &pos) const { - View *n = top()->next(); + View *bg = current_background(); + View *n = next_view(top(), bg); while (n && !n->contains(pos)) - n = n->next(); + n = next_view(n, bg); return n; } +void +View_stack::optimize_label_rec(View *cv, View *lv, Rect const &rect, Rect *optimal, + View *bg) const +{ + /* if label already fits in optimized rectangle, we are happy */ + if (optimal->fits(lv->label_sz())) + return; + + /* find next view that intersects with the rectangle or the target view */ + Rect clipped; + while (cv && cv != lv && !(clipped = outline(cv) & rect).valid()) + cv = next_view(cv, bg); + + /* reached end of view stack */ + if (!cv) + return; + + if (cv != lv && next_view(cv, bg)) + { + /* cut current view from rectangle and go into sub rectangles */ + Rect r[4] = + { Rect(rect.p1(), Point(rect.x2(), clipped.y1() - 1)), + Rect(rect.p1(), Point(clipped.x1() - 1, rect.y2())), + Rect(Point(clipped.x2() + 1, rect.y1()), rect.p2()), + Rect(Point(rect.x1(), clipped.y2() + 1), rect.p2()) }; + for (int i = 0; i < 4; i++) + optimize_label_rec(next_view(cv, bg), lv, r[i], optimal, bg); + + return; + } + + /* + * Now, cv equals lv and we must decide how to configure the + * optimal rectangle. + */ + + /* stop if label does not fit vertically */ + if (rect.h() < lv->label_sz().h()) + return; + + /* + * If label fits completely within current rectangle, we are done. + * If label's width is not fully visible, choose the widest rectangle. + */ + if (rect.fits(lv->label_sz()) || (rect.w() > optimal->w())) + *optimal = rect; +} + +void +View_stack::do_place_labels(Rect const &rect) const +{ + View *bg = current_background(); + View *start = next_view(_top.first(), bg); + /* ignore mouse cursor */ + for (View *view = start; view && next_view(view); view = next_view(view, bg)) + if ((*view & rect).valid()) + { + Rect old(view->label_pos(), view->label_sz()); + + /* calculate best visible label position */ + Rect rect = Rect(Point(0, 0), _canvas->size()) & *view; + Rect best; + optimize_label_rec(start, view, rect, &best, bg); + + /* + * If label is not fully visible, we ensure to display the first + * (most important) part. Otherwise, we center the label horizontally. + */ + int x = best.x1(); + if (best.fits(view->label_sz())) + x += (best.w() - view->label_sz().w()) / 2; + + view->label_pos(Point(x, best.y1())); + + /* refresh old and new label positions */ + refresh_view(view, view, old); + Rect n = Rect(view->label_pos(), view->label_sz()); + refresh_view(view, view, n); + } +} + }