genode/repos/os/include/decorator/window.h

299 lines
7.0 KiB
C++

/*
* \brief Window representation for decorator
* \author Norman Feske
* \date 2014-01-09
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DECORATOR__WINDOW_H_
#define _INCLUDE__DECORATOR__WINDOW_H_
/* Genode includes */
#include <util/list.h>
#include <util/string.h>
#include <util/xml_generator.h>
#include <nitpicker_session/client.h>
#include <base/snprintf.h>
/* decorator includes */
#include <decorator/types.h>
#include <decorator/xml_utils.h>
namespace Decorator {
class Canvas_base;
class Window_base;
typedef Genode::List<Window_base> Window_list;
}
class Decorator::Window_base : public Window_list::Element
{
public:
struct Border
{
unsigned top, left, right, bottom;
Border(unsigned top, unsigned left, unsigned right, unsigned bottom)
: top(top), left(left), right(right), bottom(bottom) { }
};
struct Hover
{
bool left_sizer = false,
right_sizer = false,
top_sizer = false,
bottom_sizer = false,
title = false;
unsigned window_id = 0;
bool operator != (Hover const &other) const
{
return other.left_sizer != left_sizer
|| other.right_sizer != right_sizer
|| other.top_sizer != top_sizer
|| other.bottom_sizer != bottom_sizer
|| other.title != title
|| other.window_id != window_id;
}
};
private:
Nitpicker::Session_client &_nitpicker;
/*
* Geometry of content
*/
Rect _geometry;
/*
* Unique window ID
*/
unsigned const _id;
/*
* Flag indicating that the current window position has been propagated
* to the window's corresponding nitpicker views.
*/
bool _nitpicker_views_up_to_date = false;
/*
* Flag indicating that the stacking position of the window within the
* window stack has changed. The new stacking position must be
* propagated to nitpicker.
*/
bool _nitpicker_stacking_up_to_date = false;
unsigned _topped_cnt = 0;
bool _global_to_front = false;
Nitpicker::Session::View_handle _neighbor;
Border const _border;
struct Nitpicker_view
{
Nitpicker::Session_client &_nitpicker;
Nitpicker::Session::View_handle _handle { _nitpicker.create_view() };
typedef Nitpicker::Session::Command Command;
Nitpicker_view(Nitpicker::Session_client &nitpicker, unsigned id = 0)
:
_nitpicker(nitpicker)
{
/*
* We supply the window ID as label for the anchor view.
*/
if (id) {
char buf[128];
Genode::snprintf(buf, sizeof(buf), "%d", id);
_nitpicker.enqueue<Command::Title>(_handle, buf);
}
}
~Nitpicker_view()
{
_nitpicker.destroy_view(_handle);
}
Nitpicker::Session::View_handle handle() const { return _handle; }
void stack(Nitpicker::Session::View_handle neighbor)
{
_nitpicker.enqueue<Command::To_front>(_handle, neighbor);
}
void place(Rect rect)
{
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
Point offset = Point(0, 0) - rect.p1();
_nitpicker.enqueue<Command::Offset>(_handle, offset);
}
};
Nitpicker_view _bottom_view, _right_view, _left_view, _top_view;
Nitpicker_view _content_view;
public:
Window_base(unsigned id, Nitpicker::Session_client &nitpicker,
Border border)
:
_nitpicker(nitpicker), _id(id), _border(border),
_bottom_view(nitpicker),
_right_view(nitpicker),
_left_view(nitpicker),
_top_view(nitpicker),
_content_view(nitpicker, _id)
{ }
void stack(Nitpicker::Session::View_handle neighbor)
{
_neighbor = neighbor;
_nitpicker_stacking_up_to_date = false;
}
Nitpicker::Session::View_handle frontmost_view() const
{
return _bottom_view.handle();
}
Rect outer_geometry() const
{
return Rect(_geometry.p1() - Point(_border.left, _border.top),
_geometry.p2() + Point(_border.right, _border.bottom));
}
void border_rects(Rect *top, Rect *left, Rect *right, Rect *bottom) const
{
outer_geometry().cut(_geometry, top, left, right, bottom);
}
unsigned long id() const { return _id; }
Rect geometry() const { return _geometry; }
bool is_in_front_of(Window_base const &neighbor) const
{
return _neighbor == neighbor.frontmost_view();
}
/**
* Draw window elements
*
* \param canvas graphics back end
* \param clip clipping area to apply
*/
virtual void draw(Canvas_base &canvas, Rect clip) const = 0;
/**
* Update internal window representation from XML model
*
* \return true if window changed
*
* We do not immediately update the views as part of the update
* function because at the time when updating the model, the
* decorations haven't been redrawn already. If we updated the
* nitpicker views at this point, we would reveal not-yet-drawn pixels.
*/
virtual bool update(Xml_node window_node)
{
bool result = false;
/*
* Detect the need to bring the window to the top of the global
* view stack.
*/
unsigned const topped_cnt = attribute(window_node, "topped", 0UL);
if (topped_cnt != _topped_cnt) {
_global_to_front = true;
_topped_cnt = topped_cnt;
_nitpicker_stacking_up_to_date = false;
result = true;
}
/*
* Detect geometry changes
*/
Rect new_geometry = rect_attribute(window_node);
if (new_geometry.p1() != _geometry.p1()
|| new_geometry.p2() != _geometry.p2()) {
_geometry = new_geometry;
_nitpicker_views_up_to_date = false;
result = true;
}
return result;
}
virtual void update_nitpicker_views()
{
if (!_nitpicker_views_up_to_date) {
/* update view positions */
Rect top, left, right, bottom;
border_rects(&top, &left, &right, &bottom);
_content_view.place(_geometry);
_top_view .place(top);
_left_view .place(left);
_right_view .place(right);
_bottom_view .place(bottom);
_nitpicker_views_up_to_date = true;
}
if (!_nitpicker_stacking_up_to_date) {
/*
* Bring the view to the global top of the view stack if the
* 'topped' counter changed. Otherwise, we refer to a
* session-local neighbor for the restacking operation.
*/
Nitpicker::Session::View_handle neighbor = _neighbor;
if (_global_to_front) {
neighbor = Nitpicker::Session::View_handle();
_global_to_front = false;
}
_content_view.stack(neighbor);
_top_view.stack(_content_view.handle());
_left_view.stack(_top_view.handle());
_right_view.stack(_left_view.handle());
_bottom_view.stack(_right_view.handle());
_nitpicker_stacking_up_to_date = true;
}
}
/**
* Report information about element at specified position
*
* \param position screen position
*/
virtual Hover hover(Point position) const = 0;
/**
* Return true if window needs to be redrawn event if the window layout
* model has not changed
*/
virtual bool animated() const { return false; }
};
#endif /* _INCLUDE__DECORATOR__WINDOW_H_ */