mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-19 03:06:39 +00:00
Window manager
The window manager provides a nitpicker session interface. In contrast to the nitpicker server, which leaves the view layout up to the client, the window manager organizes the views on screen according to a policy provided by a window layouter. Furthermore, it equips views with window decorations as provided by a window decorator. Both layouter and decorator are independent programs.
This commit is contained in:
parent
59555c540e
commit
acd9599890
224
repos/gems/run/wm.run
Normal file
224
repos/gems/run/wm.run
Normal file
@ -0,0 +1,224 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
set build_components {
|
||||
core init
|
||||
drivers/timer
|
||||
server/wm app/decorator app/floating_window_layouter
|
||||
server/nitpicker app/pointer server/report_rom
|
||||
drivers/framebuffer drivers/pci drivers/input
|
||||
test/nitpicker
|
||||
app/launchpad
|
||||
server/nit_fb
|
||||
}
|
||||
|
||||
lappend_if [have_spec usb] build_components drivers/usb
|
||||
lappend_if [have_spec gpio] build_components drivers/gpio
|
||||
lappend_if [have_spec imx53] build_components drivers/platform
|
||||
lappend_if [have_spec exynos5] build_components drivers/platform
|
||||
lappend_if [have_spec platform_rpi] build_components drivers/platform
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>}
|
||||
|
||||
append_if [have_spec sdl] config {
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec pci] config {
|
||||
<start name="pci_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="PCI"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec framebuffer] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec gpio] config {
|
||||
<start name="gpio_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Gpio"/></provides>
|
||||
<config/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec exynos5] config {
|
||||
<start name="platform_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Regulator"/></provides>
|
||||
<config/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec platform_rpi] config {
|
||||
<start name="platform_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Platform"/></provides>
|
||||
<config/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec imx53] config {
|
||||
<start name="platform_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Platform"/></provides>
|
||||
<config/>
|
||||
</start>
|
||||
<start name="input_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
<config/>
|
||||
</start> }
|
||||
|
||||
append_if [have_spec ps2] config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [expr ![have_spec ps2] && [have_spec usb]] config {
|
||||
<start name="usb_drv">
|
||||
<resource name="RAM" quantum="12M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
<config ehci="yes" uhci="yes" xhci="no"> <hid/> </config>
|
||||
</start> }
|
||||
|
||||
append config {
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="nitpicker">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<config>
|
||||
<domain name="pointer" layer="1" xray="no" origin="pointer" />
|
||||
<domain name="decorator" layer="2" xray="opaque" />
|
||||
<domain name="default" layer="2" />
|
||||
|
||||
<policy label="pointer" domain="pointer"/>
|
||||
<policy label="" domain="default"/>
|
||||
<policy label="wm -> decorator" domain="decorator"/>
|
||||
|
||||
<global-key name="KEY_SCROLLLOCK" operation="xray" />
|
||||
<global-key name="KEY_SYSRQ" operation="kill" />
|
||||
<global-key name="KEY_PRINT" operation="kill" />
|
||||
<global-key name="KEY_F11" operation="kill" />
|
||||
<global-key name="KEY_F12" operation="xray" />
|
||||
</config>
|
||||
</start>
|
||||
<start name="pointer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="wm">
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<route>
|
||||
<any-service>
|
||||
<child name="nitpicker"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="testnit">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="direct_testnit">
|
||||
<binary name="testnit" />
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<any-service> <child name="nitpicker"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="launchpad">
|
||||
<resource name="RAM" quantum="20M"/>
|
||||
<config>
|
||||
<launcher name="testnit" ram_quota="768K" />
|
||||
</config>
|
||||
<route>
|
||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="nit_fb">
|
||||
<resource name="RAM" quantum="20M"/>
|
||||
<config width="400" height="300" />
|
||||
<route>
|
||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core init
|
||||
timer
|
||||
wm decorator
|
||||
floating_window_layouter
|
||||
nitpicker pointer report_rom
|
||||
testnit launchpad nit_fb
|
||||
}
|
||||
|
||||
# platform-specific modules
|
||||
lappend_if [have_spec linux] boot_modules fb_sdl
|
||||
lappend_if [have_spec pci] boot_modules pci_drv
|
||||
lappend_if [have_spec ps2] boot_modules ps2_drv
|
||||
lappend_if [have_spec framebuffer] boot_modules fb_drv
|
||||
lappend_if [have_spec usb] boot_modules usb_drv
|
||||
lappend_if [have_spec gpio] boot_modules gpio_drv
|
||||
lappend_if [have_spec imx53] boot_modules platform_drv
|
||||
lappend_if [have_spec exynos5] boot_modules platform_drv
|
||||
lappend_if [have_spec platform_rpi] boot_modules platform_drv
|
||||
lappend_if [have_spec imx53] boot_modules input_drv
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -m 256 "
|
||||
|
||||
run_genode_until forever
|
683
repos/gems/src/app/floating_window_layouter/main.cc
Normal file
683
repos/gems/src/app/floating_window_layouter/main.cc
Normal file
@ -0,0 +1,683 @@
|
||||
/*
|
||||
* \brief Floating window layouter
|
||||
* \author Norman Feske
|
||||
* \date 2013-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/signal.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
#include <os/reporter.h>
|
||||
#include <input_session/connection.h>
|
||||
#include <input/event.h>
|
||||
#include <input/keycodes.h>
|
||||
#include <rom_session/connection.h>
|
||||
#include <decorator/xml_utils.h>
|
||||
|
||||
|
||||
namespace Floating_window_layouter {
|
||||
|
||||
using namespace Genode;
|
||||
struct Main;
|
||||
class Window;
|
||||
|
||||
typedef Decorator::Point Point;
|
||||
typedef Decorator::Area Area;
|
||||
typedef Decorator::Rect Rect;
|
||||
|
||||
using Decorator::attribute;
|
||||
using Decorator::string_attribute;
|
||||
using Decorator::area_attribute;
|
||||
|
||||
|
||||
static Xml_node xml_lookup_window_by_id(Xml_node node, unsigned const id)
|
||||
{
|
||||
char const *tag = "window";
|
||||
char const *id_attr = "id";
|
||||
|
||||
for (node = node.sub_node(tag); ; node = node.next(tag))
|
||||
if (attribute(node, id_attr, 0UL) == id)
|
||||
return node;
|
||||
|
||||
throw Xml_node::Nonexistent_sub_node();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if compound XML node contains a sub node with ID
|
||||
*/
|
||||
static bool xml_contains_window_node_with_id(Xml_node node,
|
||||
unsigned const id)
|
||||
{
|
||||
try { xml_lookup_window_by_id(node, id); return true; }
|
||||
catch (Xml_node::Nonexistent_sub_node) { return false; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Floating_window_layouter::Window : public List<Window>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
typedef String<256> Title;
|
||||
|
||||
struct Element
|
||||
{
|
||||
enum Type { UNDEFINED, TITLE, LEFT, RIGHT, TOP, BOTTOM,
|
||||
TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
|
||||
|
||||
Type type;
|
||||
|
||||
char const *name() const
|
||||
{
|
||||
switch (type) {
|
||||
case UNDEFINED: return "";
|
||||
case TITLE: return "title";
|
||||
case LEFT: return "left";
|
||||
case RIGHT: return "right";
|
||||
case TOP: return "top";
|
||||
case BOTTOM: return "bottom";
|
||||
case TOP_LEFT: return "top_left";
|
||||
case TOP_RIGHT: return "top_right";
|
||||
case BOTTOM_LEFT: return "bottom_left";
|
||||
case BOTTOM_RIGHT: return "bottom_right";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Element(Type type) : type(type) { }
|
||||
|
||||
bool operator != (Element const &other) const { return other.type != type; }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
unsigned const _id = 0;
|
||||
|
||||
Title _title;
|
||||
|
||||
Rect _geometry;
|
||||
|
||||
/**
|
||||
* Window geometry at the start of the current drag operation
|
||||
*/
|
||||
Rect _orig_geometry;
|
||||
|
||||
/**
|
||||
* Size as desired by the user during resize drag operations
|
||||
*/
|
||||
Area _requested_size;
|
||||
|
||||
/*
|
||||
* Number of times the window has been topped. This value is used by
|
||||
* the decorator to detect the need for bringing the window to the
|
||||
* front of nitpicker's global view stack even if the stacking order
|
||||
* stays the same within the decorator instance. This is important in
|
||||
* the presence of more than a single decorator.
|
||||
*/
|
||||
unsigned _topped_cnt = 0;
|
||||
|
||||
bool _drag_left_border = false;
|
||||
bool _drag_right_border = false;
|
||||
bool _drag_top_border = false;
|
||||
bool _drag_bottom_border = false;
|
||||
|
||||
public:
|
||||
|
||||
Window(unsigned id) : _id(id) { }
|
||||
|
||||
bool has_id(unsigned id) const { return id == _id; }
|
||||
|
||||
unsigned id() const { return _id; }
|
||||
|
||||
void title(Title const &title) { _title = title; }
|
||||
|
||||
void geometry(Rect geometry) { _geometry = geometry; }
|
||||
|
||||
Point position() const { return _geometry.p1(); }
|
||||
|
||||
void position(Point pos) { _geometry = Rect(pos, _geometry.area()); }
|
||||
|
||||
/**
|
||||
* Return true if user drags a window border
|
||||
*/
|
||||
bool _drag_border() const
|
||||
{
|
||||
return _drag_left_border || _drag_right_border
|
||||
|| _drag_top_border || _drag_bottom_border;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define window size
|
||||
*
|
||||
* This function is called when the window-list model changes.
|
||||
*/
|
||||
void size(Area size)
|
||||
{
|
||||
if (!_drag_border()) {
|
||||
_geometry = Rect(_geometry.p1(), size);
|
||||
return;
|
||||
}
|
||||
|
||||
Point p1 = _geometry.p1(), p2 = _geometry.p2();
|
||||
|
||||
if (_drag_left_border)
|
||||
p1 = Point(p2.x() - size.w() + 1, p1.y());
|
||||
|
||||
if (_drag_right_border)
|
||||
p2 = Point(p1.x() + size.w() - 1, p2.y());
|
||||
|
||||
if (_drag_top_border)
|
||||
p1 = Point(p1.x(), p2.y() - size.h() + 1);
|
||||
|
||||
if (_drag_bottom_border)
|
||||
p2 = Point(p2.x(), p1.y() + size.h() - 1);
|
||||
|
||||
_geometry = Rect(p1, p2);
|
||||
}
|
||||
|
||||
Area size() const { return _geometry.area(); }
|
||||
|
||||
Area requested_size() const { return _requested_size; }
|
||||
|
||||
void serialize(Xml_generator &xml, bool focused, Element highlight)
|
||||
{
|
||||
xml.node("window", [&]() {
|
||||
xml.attribute("id", _id);
|
||||
xml.attribute("title", _title.string());
|
||||
xml.attribute("xpos", _geometry.x1());
|
||||
xml.attribute("ypos", _geometry.y1());
|
||||
xml.attribute("width", _geometry.w());
|
||||
xml.attribute("height", _geometry.h());
|
||||
xml.attribute("topped", _topped_cnt);
|
||||
|
||||
if (focused)
|
||||
xml.attribute("focused", "yes");
|
||||
|
||||
if (highlight.type != Element::UNDEFINED) {
|
||||
xml.node("highlight", [&] () {
|
||||
xml.node(highlight.name());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user starts dragging a window element
|
||||
*/
|
||||
void initiate_drag_operation(Window::Element element)
|
||||
{
|
||||
_drag_left_border = (element.type == Window::Element::LEFT)
|
||||
|| (element.type == Window::Element::TOP_LEFT)
|
||||
|| (element.type == Window::Element::BOTTOM_LEFT);
|
||||
|
||||
_drag_right_border = (element.type == Window::Element::RIGHT)
|
||||
|| (element.type == Window::Element::TOP_RIGHT)
|
||||
|| (element.type == Window::Element::BOTTOM_RIGHT);
|
||||
|
||||
_drag_top_border = (element.type == Window::Element::TOP)
|
||||
|| (element.type == Window::Element::TOP_LEFT)
|
||||
|| (element.type == Window::Element::TOP_RIGHT);
|
||||
|
||||
_drag_bottom_border = (element.type == Window::Element::BOTTOM)
|
||||
|| (element.type == Window::Element::BOTTOM_LEFT)
|
||||
|| (element.type == Window::Element::BOTTOM_RIGHT);
|
||||
|
||||
_orig_geometry = _geometry;
|
||||
|
||||
_requested_size = _geometry.area();
|
||||
}
|
||||
|
||||
void apply_drag_operation(Point offset)
|
||||
{
|
||||
if (!_drag_border())
|
||||
position(_orig_geometry.p1() + offset);
|
||||
|
||||
int requested_w = _orig_geometry.w(),
|
||||
requested_h = _orig_geometry.h();
|
||||
|
||||
if (_drag_left_border) requested_w -= offset.x();
|
||||
if (_drag_right_border) requested_w += offset.x();
|
||||
if (_drag_top_border) requested_h -= offset.y();
|
||||
if (_drag_bottom_border) requested_h += offset.y();
|
||||
|
||||
_requested_size = Area(max(1, requested_w), max(1, requested_h));
|
||||
}
|
||||
|
||||
void finalize_drag_operation()
|
||||
{
|
||||
_requested_size = _geometry.area();
|
||||
}
|
||||
|
||||
void topped() { _topped_cnt++; }
|
||||
};
|
||||
|
||||
|
||||
struct Floating_window_layouter::Main
|
||||
{
|
||||
Signal_receiver &sig_rec;
|
||||
|
||||
List<Window> windows;
|
||||
|
||||
unsigned focused_window_id = 0;
|
||||
unsigned key_cnt = 0;
|
||||
|
||||
Window::Element hovered_element = Window::Element::UNDEFINED;
|
||||
|
||||
bool drag_state = false;
|
||||
|
||||
Window *lookup_window_by_id(unsigned id)
|
||||
{
|
||||
for (Window *w = windows.first(); w; w = w->next())
|
||||
if (w->has_id(id))
|
||||
return w;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Install handler for responding to window-list changes
|
||||
*/
|
||||
void handle_window_list_update(unsigned);
|
||||
|
||||
Signal_dispatcher<Main> window_list_dispatcher = {
|
||||
sig_rec, *this, &Main::handle_window_list_update };
|
||||
|
||||
Attached_rom_dataspace window_list { "window_list" };
|
||||
|
||||
|
||||
/**
|
||||
* Install handler for responding to hover changes
|
||||
*/
|
||||
void handle_hover_update(unsigned);
|
||||
|
||||
Signal_dispatcher<Main> hover_dispatcher = {
|
||||
sig_rec, *this, &Main::handle_hover_update };
|
||||
|
||||
Attached_rom_dataspace hover { "hover" };
|
||||
|
||||
|
||||
/**
|
||||
* Install handler for responding to user input
|
||||
*/
|
||||
void handle_input(unsigned);
|
||||
|
||||
Signal_dispatcher<Main> input_dispatcher = {
|
||||
sig_rec, *this, &Main::handle_input };
|
||||
|
||||
Input::Connection input;
|
||||
|
||||
Attached_dataspace input_ds { input.dataspace() };
|
||||
|
||||
Reporter window_layout_reporter = { "window_layout" };
|
||||
Reporter resize_request_reporter = { "resize_request" };
|
||||
Reporter focus_reporter = { "focus" };
|
||||
|
||||
unsigned dragged_window_id = 0;
|
||||
|
||||
Point pointer_clicked;
|
||||
Point pointer_last;
|
||||
Point pointer_curr;
|
||||
|
||||
void import_window_list(Xml_node);
|
||||
void generate_window_layout_model();
|
||||
void generate_resize_request_model();
|
||||
void generate_focus_model();
|
||||
void initiate_window_drag(Window &window);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Main(Signal_receiver &sig_rec) : sig_rec(sig_rec)
|
||||
{
|
||||
window_list.sigh(window_list_dispatcher);
|
||||
|
||||
hover.sigh(hover_dispatcher);
|
||||
|
||||
input.sigh(input_dispatcher);
|
||||
|
||||
window_layout_reporter.enabled(true);
|
||||
resize_request_reporter.enabled(true);
|
||||
focus_reporter.enabled(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::import_window_list(Xml_node window_list_xml)
|
||||
{
|
||||
char const *tag = "window";
|
||||
|
||||
/*
|
||||
* Remove windows from layout that are no longer in the window list
|
||||
*/
|
||||
for (Window *win = windows.first(), *next = 0; win; win = next) {
|
||||
next = win->next();
|
||||
if (!xml_contains_window_node_with_id(window_list_xml, win->id())) {
|
||||
windows.remove(win);
|
||||
destroy(env()->heap(), win);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update window attributes, add new windows to the layout
|
||||
*/
|
||||
try {
|
||||
for (Xml_node node = window_list_xml.sub_node(tag); ; node = node.next(tag)) {
|
||||
|
||||
unsigned long id = 0;
|
||||
node.attribute("id").value(&id);
|
||||
|
||||
Window *win = lookup_window_by_id(id);
|
||||
if (!win) {
|
||||
win = new (env()->heap()) Window(id);
|
||||
windows.insert(win);
|
||||
|
||||
/*
|
||||
* Define initial window position
|
||||
*/
|
||||
win->position(Point(150*id % 800, 30 + (100*id % 500)));
|
||||
}
|
||||
|
||||
win->size(area_attribute(node));
|
||||
win->title(string_attribute(node, "title", Window::Title("untitled")));
|
||||
}
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::generate_window_layout_model()
|
||||
{
|
||||
Reporter::Xml_generator xml(window_layout_reporter, [&] ()
|
||||
{
|
||||
for (Window *w = windows.first(); w; w = w->next()) {
|
||||
|
||||
bool const is_focused = w->has_id(focused_window_id);
|
||||
|
||||
Window::Element const highlight =
|
||||
is_focused ? hovered_element : Window::Element::UNDEFINED;
|
||||
|
||||
w->serialize(xml, is_focused, highlight);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::generate_resize_request_model()
|
||||
{
|
||||
Reporter::Xml_generator xml(resize_request_reporter, [&] ()
|
||||
{
|
||||
Window const *dragged_window = lookup_window_by_id(dragged_window_id);
|
||||
if (dragged_window) {
|
||||
|
||||
Area const requested_size = dragged_window->requested_size();
|
||||
if (requested_size != dragged_window->size()) {
|
||||
xml.node("window", [&] () {
|
||||
xml.attribute("id", dragged_window_id);
|
||||
xml.attribute("width", requested_size.w());
|
||||
xml.attribute("height", requested_size.h());
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::generate_focus_model()
|
||||
{
|
||||
Reporter::Xml_generator xml(focus_reporter, [&] ()
|
||||
{
|
||||
xml.node("window", [&] () {
|
||||
xml.attribute("id", focused_window_id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine window element that corresponds to hover model
|
||||
*/
|
||||
static Floating_window_layouter::Window::Element
|
||||
element_from_hover_model(Genode::Xml_node hover_window_xml)
|
||||
{
|
||||
typedef Floating_window_layouter::Window::Element::Type Type;
|
||||
|
||||
bool const left_sizer = hover_window_xml.has_sub_node("left_sizer"),
|
||||
right_sizer = hover_window_xml.has_sub_node("right_sizer"),
|
||||
top_sizer = hover_window_xml.has_sub_node("top_sizer"),
|
||||
bottom_sizer = hover_window_xml.has_sub_node("bottom_sizer");
|
||||
|
||||
if (left_sizer && top_sizer) return Type::TOP_LEFT;
|
||||
if (left_sizer && bottom_sizer) return Type::BOTTOM_LEFT;
|
||||
if (left_sizer) return Type::LEFT;
|
||||
|
||||
if (right_sizer && top_sizer) return Type::TOP_RIGHT;
|
||||
if (right_sizer && bottom_sizer) return Type::BOTTOM_RIGHT;
|
||||
if (right_sizer) return Type::RIGHT;
|
||||
|
||||
if (top_sizer) return Type::TOP;
|
||||
if (bottom_sizer) return Type::BOTTOM;
|
||||
|
||||
if (hover_window_xml.has_sub_node("title")) return Type::TITLE;
|
||||
|
||||
return Type::UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::initiate_window_drag(Window &window)
|
||||
{
|
||||
window.initiate_drag_operation(hovered_element);
|
||||
|
||||
/* bring focused window to front */
|
||||
if (&window != windows.first()) {
|
||||
windows.remove(&window);
|
||||
windows.insert(&window);
|
||||
}
|
||||
|
||||
window.topped();
|
||||
}
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::handle_window_list_update(unsigned)
|
||||
{
|
||||
window_list.update();
|
||||
|
||||
try {
|
||||
import_window_list(Xml_node(window_list.local_addr<char>())); }
|
||||
catch (...) {
|
||||
PERR("Error while importing window list"); }
|
||||
|
||||
generate_window_layout_model();
|
||||
}
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::handle_hover_update(unsigned)
|
||||
{
|
||||
hover.update();
|
||||
|
||||
try {
|
||||
Xml_node const hover_xml(hover.local_addr<char>());
|
||||
|
||||
Xml_node const hover_window_xml = hover_xml.sub_node("window");
|
||||
|
||||
unsigned const id = attribute(hover_window_xml, "id", 0UL);
|
||||
|
||||
Window::Element hovered = element_from_hover_model(hover_window_xml);
|
||||
|
||||
/*
|
||||
* Check if we have just received an update while already being in
|
||||
* dragged state.
|
||||
*
|
||||
* This can happen when the user selects a new nitpicker domain by
|
||||
* clicking on a window decoration. Prior the click, the new session is
|
||||
* not aware of the current mouse position. So the hover model is not
|
||||
* up to date. As soon as nitpicker assigns the focus to the new
|
||||
* session and delivers the corresponding press event, we enter the
|
||||
* drag state (in the 'handle_input' function. But we don't know which
|
||||
* window is dragged until the decorator updates the hover model. Now,
|
||||
* when the model is updated and we are still in dragged state, we can
|
||||
* finally initiate the window-drag operation for the now-known window.
|
||||
*/
|
||||
if (id && drag_state && dragged_window_id == 0)
|
||||
{
|
||||
dragged_window_id = id;
|
||||
focused_window_id = id;
|
||||
|
||||
Window *window = lookup_window_by_id(id);
|
||||
if (window) {
|
||||
initiate_window_drag(*window);
|
||||
generate_window_layout_model();
|
||||
generate_focus_model();
|
||||
}
|
||||
}
|
||||
|
||||
if (!drag_state && (id != focused_window_id || hovered != hovered_element)) {
|
||||
|
||||
focused_window_id = id;
|
||||
hovered_element = hovered;
|
||||
generate_window_layout_model();
|
||||
generate_focus_model();
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
/* reset focused window if pointer does not hover over any window */
|
||||
if (!drag_state) {
|
||||
hovered_element = Window::Element::UNDEFINED;
|
||||
generate_window_layout_model();
|
||||
generate_focus_model();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Floating_window_layouter::Main::handle_input(unsigned)
|
||||
{
|
||||
bool need_regenerate_window_layout_model = false;
|
||||
bool need_regenerate_resize_request_model = false;
|
||||
|
||||
Window *focused_window = lookup_window_by_id(focused_window_id);
|
||||
|
||||
while (input.is_pending()) {
|
||||
|
||||
size_t const num_events = input.flush();
|
||||
|
||||
Input::Event const * const ev = input_ds.local_addr<Input::Event>();
|
||||
|
||||
for (size_t i = 0; i < num_events; i++) {
|
||||
|
||||
Input::Event e = ev[i];
|
||||
|
||||
if (e.type() == Input::Event::MOTION
|
||||
|| e.type() == Input::Event::FOCUS)
|
||||
pointer_curr = Point(e.ax(), e.ay());
|
||||
|
||||
/* track number of pressed buttons/keys */
|
||||
if (e.type() == Input::Event::PRESS) key_cnt++;
|
||||
if (e.type() == Input::Event::RELEASE) key_cnt--;
|
||||
|
||||
if (e.type() == Input::Event::PRESS
|
||||
&& e.keycode() == Input::BTN_LEFT) {
|
||||
|
||||
drag_state = true;
|
||||
dragged_window_id = focused_window_id;
|
||||
pointer_clicked = pointer_curr;
|
||||
pointer_last = pointer_clicked;
|
||||
|
||||
/*
|
||||
* If the focused window is known at the time of the press
|
||||
* event, we can initiate the drag operation immediately.
|
||||
* Otherwise, we the initiation is deferred to the next
|
||||
* update of the hover model.
|
||||
*/
|
||||
if (focused_window) {
|
||||
initiate_window_drag(*focused_window);
|
||||
need_regenerate_window_layout_model = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* detect end of drag operation */
|
||||
if (e.type() == Input::Event::RELEASE) {
|
||||
if (key_cnt == 0) {
|
||||
drag_state = false;
|
||||
generate_focus_model();
|
||||
|
||||
Window *dragged_window = lookup_window_by_id(dragged_window_id);
|
||||
if (dragged_window) {
|
||||
|
||||
Area const last_requested_size = dragged_window->requested_size();
|
||||
dragged_window->finalize_drag_operation();
|
||||
|
||||
if (last_requested_size != dragged_window->requested_size())
|
||||
need_regenerate_resize_request_model = true;
|
||||
|
||||
/*
|
||||
* Update window layout because highlighting may have
|
||||
* changed after the drag operation. E.g., if the
|
||||
* window has not kept up with the dragging of a
|
||||
* resize handle, the resize handle is no longer
|
||||
* hovered.
|
||||
*/
|
||||
handle_hover_update(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (drag_state && (pointer_curr != pointer_last)) {
|
||||
|
||||
pointer_last = pointer_curr;
|
||||
|
||||
Window *dragged_window = lookup_window_by_id(dragged_window_id);
|
||||
if (dragged_window) {
|
||||
|
||||
Point const last_pos = dragged_window->position();
|
||||
Area const last_requested_size = dragged_window->requested_size();
|
||||
|
||||
dragged_window->apply_drag_operation(pointer_curr - pointer_clicked);
|
||||
|
||||
if (last_pos != dragged_window->position())
|
||||
need_regenerate_window_layout_model = true;
|
||||
|
||||
if (last_requested_size != dragged_window->requested_size())
|
||||
need_regenerate_resize_request_model = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_regenerate_window_layout_model)
|
||||
generate_window_layout_model();
|
||||
|
||||
if (need_regenerate_resize_request_model)
|
||||
generate_resize_request_model();
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static Genode::Signal_receiver sig_rec;
|
||||
|
||||
static Floating_window_layouter::Main application(sig_rec);
|
||||
|
||||
/* import initial state */
|
||||
application.handle_window_list_update(0);
|
||||
|
||||
/* process incoming signals */
|
||||
for (;;) {
|
||||
using namespace Genode;
|
||||
|
||||
Signal sig = sig_rec.wait_for_signal();
|
||||
Signal_dispatcher_base *dispatcher =
|
||||
dynamic_cast<Signal_dispatcher_base *>(sig.context());
|
||||
|
||||
if (dispatcher)
|
||||
dispatcher->dispatch(sig.num());
|
||||
}
|
||||
}
|
4
repos/gems/src/app/floating_window_layouter/target.mk
Normal file
4
repos/gems/src/app/floating_window_layouter/target.mk
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = floating_window_layouter
|
||||
SRC_CC = main.cc
|
||||
LIBS = base cxx
|
||||
|
473
repos/gems/src/server/wm/decorator_nitpicker.h
Normal file
473
repos/gems/src/server/wm/decorator_nitpicker.h
Normal file
@ -0,0 +1,473 @@
|
||||
/*
|
||||
* \brief Local nitpicker service provided to decorator
|
||||
* \author Norman Feske
|
||||
* \date 2014-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _DECORATOR_NITPICKER_H_
|
||||
#define _DECORATOR_NITPICKER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/string.h>
|
||||
#include <os/server.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <nitpicker_session/connection.h>
|
||||
#include <input_session/client.h>
|
||||
#include <input/event.h>
|
||||
#include <input/component.h>
|
||||
|
||||
/* local includes */
|
||||
#include <window_registry.h>
|
||||
|
||||
namespace Wm { class Main;
|
||||
using Genode::size_t;
|
||||
using Genode::Allocator;
|
||||
using Server::Entrypoint;
|
||||
using Genode::Ram_session_client;
|
||||
using Genode::Ram_session_capability;
|
||||
using Genode::Arg_string;
|
||||
using Genode::Object_pool;
|
||||
using Genode::Attached_dataspace;
|
||||
using Genode::Attached_ram_dataspace;
|
||||
using Genode::Signal_rpc_member;
|
||||
}
|
||||
|
||||
|
||||
namespace Wm {
|
||||
|
||||
struct Decorator_nitpicker_session;
|
||||
struct Decorator_nitpicker_service;
|
||||
struct Decorator_content_callback;
|
||||
struct Decorator_content_registry;
|
||||
}
|
||||
|
||||
|
||||
struct Wm::Decorator_content_callback
|
||||
{
|
||||
virtual void content_geometry(Window_registry::Id win_id, Rect rect) = 0;
|
||||
|
||||
virtual Nitpicker::View_capability content_view(Window_registry::Id win_id) = 0;
|
||||
|
||||
virtual void update_content_child_views(Window_registry::Id win_id) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Wm::Decorator_content_registry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Exception type
|
||||
*/
|
||||
struct Lookup_failed { };
|
||||
|
||||
private:
|
||||
|
||||
struct Entry : List<Entry>::Element
|
||||
{
|
||||
Nitpicker::Session::View_handle const decorator_view_handle;
|
||||
Window_registry::Id const win_id;
|
||||
|
||||
Entry(Nitpicker::Session::View_handle decorator_view_handle,
|
||||
Window_registry::Id win_id)
|
||||
:
|
||||
decorator_view_handle(decorator_view_handle),
|
||||
win_id(win_id)
|
||||
{ }
|
||||
};
|
||||
|
||||
List<Entry> _list;
|
||||
Allocator &_entry_alloc;
|
||||
|
||||
Entry const &_lookup(Nitpicker::Session::View_handle view_handle) const
|
||||
{
|
||||
for (Entry const *e = _list.first(); e; e = e->next()) {
|
||||
if (e->decorator_view_handle == view_handle)
|
||||
return *e;
|
||||
}
|
||||
|
||||
throw Lookup_failed();
|
||||
}
|
||||
|
||||
void _remove(Entry const &e)
|
||||
{
|
||||
_list.remove(&e);
|
||||
destroy(_entry_alloc, const_cast<Entry *>(&e));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Decorator_content_registry(Allocator &entry_alloc)
|
||||
:
|
||||
_entry_alloc(entry_alloc)
|
||||
{ }
|
||||
|
||||
~Decorator_content_registry()
|
||||
{
|
||||
while (Entry *e = _list.first())
|
||||
_remove(*e);
|
||||
}
|
||||
|
||||
void insert(Nitpicker::Session::View_handle decorator_view_handle,
|
||||
Window_registry::Id win_id)
|
||||
{
|
||||
Entry *e = new (_entry_alloc) Entry(decorator_view_handle, win_id);
|
||||
_list.insert(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup window ID for a given decorator content view
|
||||
*
|
||||
* \throw Lookup_failed
|
||||
*/
|
||||
Window_registry::Id lookup(Nitpicker::Session::View_handle view_handle) const
|
||||
{
|
||||
return _lookup(view_handle).win_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove entry
|
||||
*
|
||||
* \throw Lookup_failed
|
||||
*/
|
||||
void remove(Nitpicker::Session::View_handle view_handle)
|
||||
{
|
||||
_remove(_lookup(view_handle));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Wm::Decorator_nitpicker_session : Genode::Rpc_object<Nitpicker::Session>
|
||||
{
|
||||
typedef Nitpicker::View_capability View_capability;
|
||||
typedef Nitpicker::Session::View_handle View_handle;
|
||||
|
||||
Ram_session_client _ram;
|
||||
|
||||
Nitpicker::Connection _nitpicker_session { "decorator" };
|
||||
|
||||
typedef Nitpicker::Session::Command_buffer Command_buffer;
|
||||
|
||||
Attached_ram_dataspace _command_ds { &_ram, sizeof(Command_buffer) };
|
||||
|
||||
Command_buffer &_command_buffer = *_command_ds.local_addr<Command_buffer>();
|
||||
|
||||
Input::Session_client _nitpicker_input { _nitpicker_session.input_session() };
|
||||
|
||||
Attached_dataspace _nitpicker_input_ds { _nitpicker_input.dataspace() };
|
||||
|
||||
Local_reporter &_pointer_reporter;
|
||||
|
||||
Input::Session_component &_window_layouter_input;
|
||||
|
||||
Decorator_content_callback &_content_callback;
|
||||
|
||||
/* XXX don't allocate content-registry entries from heap */
|
||||
Decorator_content_registry _content_registry { *Genode::env()->heap() };
|
||||
|
||||
Entrypoint &_ep;
|
||||
|
||||
Allocator &_md_alloc;
|
||||
|
||||
Signal_rpc_member<Decorator_nitpicker_session>
|
||||
_input_dispatcher { _ep, *this, &Decorator_nitpicker_session::_input_handler };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ep entrypoint used for dispatching signals
|
||||
*/
|
||||
Decorator_nitpicker_session(Ram_session_capability ram,
|
||||
Entrypoint &ep, Allocator &md_alloc,
|
||||
Local_reporter &pointer_reporter,
|
||||
Input::Session_component &window_layouter_input,
|
||||
Decorator_content_callback &content_callback)
|
||||
:
|
||||
_ram(ram),
|
||||
_pointer_reporter(pointer_reporter),
|
||||
_window_layouter_input(window_layouter_input),
|
||||
_content_callback(content_callback),
|
||||
_ep(ep), _md_alloc(md_alloc)
|
||||
{
|
||||
_nitpicker_input.sigh(_input_dispatcher);
|
||||
}
|
||||
|
||||
void _input_handler(unsigned)
|
||||
{
|
||||
Input::Event const * const events =
|
||||
_nitpicker_input_ds.local_addr<Input::Event>();
|
||||
|
||||
while (_nitpicker_input.is_pending()) {
|
||||
|
||||
size_t const num_events = _nitpicker_input.flush();
|
||||
|
||||
/* we trust nitpicker to return a valid number of events */
|
||||
|
||||
for (size_t i = 0; i < num_events; i++) {
|
||||
|
||||
Input::Event const &ev = events[i];
|
||||
|
||||
if (ev.type() == Input::Event::MOTION) {
|
||||
Local_reporter::Xml_generator xml(_pointer_reporter, [&] ()
|
||||
{
|
||||
xml.attribute("xpos", ev.ax());
|
||||
xml.attribute("ypos", ev.ay());
|
||||
});
|
||||
}
|
||||
|
||||
if (ev.type() == Input::Event::LEAVE) {
|
||||
|
||||
Local_reporter::Xml_generator xml(_pointer_reporter, [&] ()
|
||||
{
|
||||
/* report empty pointer model */
|
||||
});
|
||||
}
|
||||
|
||||
_window_layouter_input.submit(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _execute_command(Command const &cmd)
|
||||
{
|
||||
switch (cmd.opcode) {
|
||||
|
||||
case Command::OP_TITLE:
|
||||
{
|
||||
unsigned long id = 0;
|
||||
Genode::ascii_to(cmd.title.title.string(), &id);
|
||||
|
||||
if (id > 0)
|
||||
_content_registry.insert(cmd.title.view,
|
||||
Window_registry::Id(id));
|
||||
return;
|
||||
}
|
||||
|
||||
case Command::OP_TO_FRONT:
|
||||
|
||||
try {
|
||||
|
||||
/*
|
||||
* If the content view is re-stacked, replace it by the real
|
||||
* window content.
|
||||
*
|
||||
* The lookup fails with an exception for non-content views.
|
||||
* In this case, forward the command.
|
||||
*/
|
||||
Window_registry::Id win_id = _content_registry.lookup(cmd.to_front.view);
|
||||
|
||||
/*
|
||||
* Replace content view originally created by the decorator
|
||||
* by view that shows the real window content.
|
||||
*/
|
||||
Nitpicker::View_capability view_cap =
|
||||
_content_callback.content_view(win_id);
|
||||
|
||||
_nitpicker_session.view_handle(view_cap,
|
||||
cmd.to_front.view);
|
||||
|
||||
_nitpicker_session.enqueue(cmd);
|
||||
_nitpicker_session.execute();
|
||||
|
||||
/*
|
||||
* Now that the physical content view exists, it is time
|
||||
* to revisit the child views.
|
||||
*/
|
||||
_content_callback.update_content_child_views(win_id);
|
||||
|
||||
} catch (Decorator_content_registry::Lookup_failed) {
|
||||
|
||||
_nitpicker_session.enqueue(cmd);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case Command::OP_GEOMETRY:
|
||||
|
||||
try {
|
||||
|
||||
/*
|
||||
* If the content view changes position, propagate the new
|
||||
* position to the nitpicker service to properly transform
|
||||
* absolute input coordinates.
|
||||
*/
|
||||
Window_registry::Id win_id = _content_registry.lookup(cmd.geometry.view);
|
||||
|
||||
_content_callback.content_geometry(win_id, cmd.geometry.rect);
|
||||
}
|
||||
catch (Decorator_content_registry::Lookup_failed) { }
|
||||
|
||||
/* forward command */
|
||||
_nitpicker_session.enqueue(cmd);
|
||||
return;
|
||||
|
||||
case Command::OP_OFFSET:
|
||||
|
||||
try {
|
||||
|
||||
/*
|
||||
* If non-content views change their offset (if the lookup
|
||||
* fails), propagate the event
|
||||
*/
|
||||
_content_registry.lookup(cmd.geometry.view);
|
||||
}
|
||||
catch (Decorator_content_registry::Lookup_failed) {
|
||||
_nitpicker_session.enqueue(cmd);
|
||||
}
|
||||
return;
|
||||
|
||||
case Command::OP_TO_BACK:
|
||||
case Command::OP_BACKGROUND:
|
||||
case Command::OP_NOP:
|
||||
|
||||
_nitpicker_session.enqueue(cmd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void upgrade(const char *args)
|
||||
{
|
||||
Genode::env()->parent()->upgrade(_nitpicker_session, args);
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
** Nitpicker session interface **
|
||||
*********************************/
|
||||
|
||||
Framebuffer::Session_capability framebuffer_session() override
|
||||
{
|
||||
return _nitpicker_session.framebuffer_session();
|
||||
}
|
||||
|
||||
Input::Session_capability input_session() override
|
||||
{
|
||||
/*
|
||||
* Deny input to the decorator. User input referring to the
|
||||
* window decorations is routed to the window manager.
|
||||
*/
|
||||
return Input::Session_capability();
|
||||
}
|
||||
|
||||
View_handle create_view(View_handle parent) override
|
||||
{
|
||||
return _nitpicker_session.create_view(parent);
|
||||
}
|
||||
|
||||
void destroy_view(View_handle view) override
|
||||
{
|
||||
_nitpicker_session.destroy_view(view);
|
||||
}
|
||||
|
||||
View_handle view_handle(View_capability view_cap, View_handle handle) override
|
||||
{
|
||||
return _nitpicker_session.view_handle(view_cap, handle);
|
||||
}
|
||||
|
||||
View_capability view_capability(View_handle view) override
|
||||
{
|
||||
return _nitpicker_session.view_capability(view);
|
||||
}
|
||||
|
||||
void release_view_handle(View_handle view) override
|
||||
{
|
||||
/* XXX dealloc View_ptr */
|
||||
_nitpicker_session.release_view_handle(view);
|
||||
}
|
||||
|
||||
Genode::Dataspace_capability command_dataspace() override
|
||||
{
|
||||
return _command_ds.cap();
|
||||
}
|
||||
|
||||
void execute() override
|
||||
{
|
||||
for (unsigned i = 0; i < _command_buffer.num(); i++) {
|
||||
try {
|
||||
_execute_command(_command_buffer.get(i));
|
||||
}
|
||||
catch (...) {
|
||||
PWRN("unhandled exception while processing command from decorator");
|
||||
}
|
||||
}
|
||||
_nitpicker_session.execute();
|
||||
}
|
||||
|
||||
Framebuffer::Mode mode() override
|
||||
{
|
||||
return _nitpicker_session.mode();
|
||||
}
|
||||
|
||||
void mode_sigh(Genode::Signal_context_capability sigh) override
|
||||
{
|
||||
_nitpicker_session.mode_sigh(sigh);
|
||||
}
|
||||
|
||||
void buffer(Framebuffer::Mode mode, bool use_alpha) override
|
||||
{
|
||||
_nitpicker_session.buffer(mode, use_alpha);
|
||||
}
|
||||
|
||||
void focus(Genode::Capability<Nitpicker::Session>) { }
|
||||
};
|
||||
|
||||
|
||||
struct Wm::Decorator_nitpicker_service : Genode::Service, Genode::Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
Entrypoint &_ep;
|
||||
Allocator &_md_alloc;
|
||||
Ram_session_capability _ram;
|
||||
Local_reporter &_pointer_reporter;
|
||||
Input::Session_component &_window_layouter_input;
|
||||
Decorator_content_callback &_content_callback;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Decorator_nitpicker_service(Entrypoint &ep, Allocator &md_alloc,
|
||||
Ram_session_capability ram,
|
||||
Local_reporter &pointer_reporter,
|
||||
Input::Session_component &window_layouter_input,
|
||||
Decorator_content_callback &content_callback)
|
||||
:
|
||||
Service("Nitpicker"),
|
||||
_ep(ep), _md_alloc(md_alloc),
|
||||
_ram(ram), _pointer_reporter(pointer_reporter),
|
||||
_window_layouter_input(window_layouter_input),
|
||||
_content_callback(content_callback)
|
||||
{ }
|
||||
|
||||
Genode::Session_capability
|
||||
session(const char *, Genode::Affinity const &) override
|
||||
{
|
||||
Decorator_nitpicker_session *s = new (_md_alloc)
|
||||
Decorator_nitpicker_session(_ram, _ep, _md_alloc,
|
||||
_pointer_reporter,
|
||||
_window_layouter_input,
|
||||
_content_callback);
|
||||
|
||||
return _ep.manage(*s);
|
||||
}
|
||||
|
||||
void upgrade(Genode::Session_capability session, const char *args) override
|
||||
{
|
||||
typedef typename Object_pool<Decorator_nitpicker_session>::Guard Object_guard;
|
||||
Object_guard np_session(_ep.rpc_ep().lookup_and_lock(session));
|
||||
|
||||
if (np_session)
|
||||
np_session->upgrade(args);
|
||||
}
|
||||
|
||||
void close(Genode::Session_capability) { }
|
||||
};
|
||||
|
||||
#endif /* _DECORATOR_NITPICKER_H_ */
|
128
repos/gems/src/server/wm/decorator_slave.h
Normal file
128
repos/gems/src/server/wm/decorator_slave.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* \brief Slave for drawing window decorations
|
||||
* \author Norman Feske
|
||||
* \date 2014-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _DECORATOR_SLAVE_H_
|
||||
#define _DECORATOR_SLAVE_H_
|
||||
|
||||
namespace Wm {
|
||||
|
||||
class Decorator_slave;
|
||||
|
||||
using Genode::Rom_session_capability;
|
||||
using Genode::Capability;
|
||||
}
|
||||
|
||||
|
||||
class Wm::Decorator_slave
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Ram_session &_ram;
|
||||
|
||||
class Policy : public Genode::Slave_policy
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Service &_nitpicker_service;
|
||||
|
||||
Single_session_service _window_layout_rom_service;
|
||||
Single_session_service _pointer_rom_service;
|
||||
Single_session_service _hover_report_service;
|
||||
|
||||
protected:
|
||||
|
||||
char const **_permitted_services() const
|
||||
{
|
||||
static char const *permitted_services[] = {
|
||||
"CAP", "LOG", "SIGNAL", "RM", 0 };
|
||||
|
||||
return permitted_services;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Policy(Genode::Rpc_entrypoint &entrypoint,
|
||||
Genode::Ram_session &ram,
|
||||
Genode::Service &nitpicker_service,
|
||||
Rom_session_capability window_layout_rom,
|
||||
Rom_session_capability pointer_rom,
|
||||
Genode::Capability<Report::Session> hover_report)
|
||||
:
|
||||
Slave_policy("decorator", entrypoint, &ram),
|
||||
_nitpicker_service(nitpicker_service),
|
||||
_window_layout_rom_service("ROM", window_layout_rom),
|
||||
_pointer_rom_service("ROM", pointer_rom),
|
||||
_hover_report_service("Report", hover_report)
|
||||
|
||||
{ }
|
||||
|
||||
Genode::Service *resolve_session_request(const char *service_name,
|
||||
const char *args) override
|
||||
{
|
||||
using Genode::strcmp;
|
||||
|
||||
if (strcmp(service_name, "Nitpicker") == 0)
|
||||
return &_nitpicker_service;
|
||||
|
||||
char label[128];
|
||||
Arg_string::find_arg(args, "label").string(label, sizeof(label), "");
|
||||
|
||||
if (strcmp(service_name, "ROM") == 0) {
|
||||
|
||||
if (strcmp(label, "decorator -> window_layout") == 0)
|
||||
return &_window_layout_rom_service;
|
||||
|
||||
if (strcmp(label, "decorator -> pointer") == 0)
|
||||
return &_pointer_rom_service;
|
||||
}
|
||||
|
||||
if (strcmp(service_name, "Report") == 0) {
|
||||
|
||||
if (strcmp(label, "decorator -> hover") == 0)
|
||||
return &_hover_report_service;
|
||||
}
|
||||
|
||||
return Genode::Slave_policy::resolve_session_request(service_name, args);
|
||||
}
|
||||
};
|
||||
|
||||
Genode::size_t const _ep_stack_size = 4*1024*sizeof(Genode::addr_t);
|
||||
Genode::Rpc_entrypoint _ep;
|
||||
Policy _policy;
|
||||
Genode::size_t const _quota = 4*1024*1024;
|
||||
Genode::Slave _slave;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ram RAM session for paying nitpicker sessions created
|
||||
* by the decorator
|
||||
*/
|
||||
Decorator_slave(Genode::Cap_session &cap,
|
||||
Genode::Service &nitpicker_service,
|
||||
Genode::Ram_session &ram,
|
||||
Rom_session_capability window_layout_rom,
|
||||
Rom_session_capability pointer_rom,
|
||||
Genode::Capability<Report::Session> hover_report)
|
||||
:
|
||||
_ram(ram),
|
||||
_ep(&cap, _ep_stack_size, "decorator"),
|
||||
_policy(_ep, ram, nitpicker_service, window_layout_rom,
|
||||
pointer_rom, hover_report),
|
||||
_slave(_ep, _policy, _quota)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _DECORATOR_SLAVE_H_ */
|
52
repos/gems/src/server/wm/local_reporter.h
Normal file
52
repos/gems/src/server/wm/local_reporter.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* \brief Utility for producing reports to a report session
|
||||
* \author Norman Feske
|
||||
* \date 2014-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _LOCAL_REPORTER_H_
|
||||
#define _LOCAL_REPORTER_H_
|
||||
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <util/xml_generator.h>
|
||||
#include <report_session/client.h>
|
||||
|
||||
|
||||
namespace Wm { struct Local_reporter; }
|
||||
|
||||
struct Wm::Local_reporter
|
||||
{
|
||||
Report::Session_client _session;
|
||||
|
||||
Genode::Attached_dataspace _ds;
|
||||
|
||||
char const *_name;
|
||||
|
||||
Local_reporter(char const *name, Genode::Capability<Report::Session> session_cap)
|
||||
:
|
||||
_session(session_cap), _ds(_session.dataspace()), _name(name)
|
||||
{ }
|
||||
|
||||
struct Xml_generator : public Genode::Xml_generator
|
||||
{
|
||||
template <typename FUNC>
|
||||
Xml_generator(Local_reporter &reporter, FUNC const &func)
|
||||
:
|
||||
Genode::Xml_generator(reporter._ds.local_addr<char>(),
|
||||
reporter._ds.size(),
|
||||
reporter._name,
|
||||
func)
|
||||
{
|
||||
reporter._session.submit(used());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _LOCAL_REPORTER_H_ */
|
185
repos/gems/src/server/wm/main.cc
Normal file
185
repos/gems/src/server/wm/main.cc
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* \brief Window manager
|
||||
* \author Norman Feske
|
||||
* \date 2014-01-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/server.h>
|
||||
#include <nitpicker_session/client.h>
|
||||
#include <framebuffer_session/client.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <util/volatile_object.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
/* local includes */
|
||||
#include <single_session_service.h>
|
||||
#include <report_rom_slave.h>
|
||||
#include <decorator_nitpicker.h>
|
||||
#include <local_reporter.h>
|
||||
#include <decorator_slave.h>
|
||||
#include <window_layouter_slave.h>
|
||||
#include <nitpicker.h>
|
||||
|
||||
namespace Wm {
|
||||
|
||||
class Main;
|
||||
|
||||
using Genode::size_t;
|
||||
using Genode::env;
|
||||
using Genode::Rom_session_client;
|
||||
using Genode::Rom_connection;
|
||||
using Genode::Xml_node;
|
||||
}
|
||||
|
||||
|
||||
struct Wm::Main
|
||||
{
|
||||
Server::Entrypoint ep;
|
||||
|
||||
Genode::Cap_connection cap;
|
||||
|
||||
Report_rom_slave report_rom_slave = { cap, *env()->ram_session() };
|
||||
|
||||
Rom_session_capability window_list_rom = report_rom_slave.rom_session("window_list");
|
||||
Rom_session_capability window_layout_rom = report_rom_slave.rom_session("window_layout");
|
||||
Rom_session_capability pointer_rom = report_rom_slave.rom_session("pointer");
|
||||
Rom_session_capability hover_rom = report_rom_slave.rom_session("hover");
|
||||
|
||||
Rom_session_client focus_rom { report_rom_slave.rom_session("focus") };
|
||||
Rom_session_client resize_request_rom { report_rom_slave.rom_session("resize_request") };
|
||||
|
||||
/* pointer position reported by nitpicker */
|
||||
Capability<Report::Session> pointer_report = report_rom_slave.report_session("pointer");
|
||||
Local_reporter pointer_reporter = { "pointer", pointer_report };
|
||||
|
||||
/* hovered element reported by decorator */
|
||||
Capability<Report::Session> hover_report = report_rom_slave.report_session("hover");
|
||||
|
||||
Capability<Report::Session> window_list_report = report_rom_slave.report_session("window_list");
|
||||
Local_reporter window_list_reporter = { "window_list", window_list_report };
|
||||
|
||||
Capability<Report::Session> window_layout_report = report_rom_slave.report_session("window_layout");
|
||||
Capability<Report::Session> resize_request_report = report_rom_slave.report_session("resize_request");
|
||||
Capability<Report::Session> focus_report = report_rom_slave.report_session("focus");
|
||||
|
||||
Input::Session_component window_layouter_input;
|
||||
|
||||
Window_registry window_registry { *env()->heap(), window_list_reporter };
|
||||
|
||||
Nitpicker::Root nitpicker_root { ep, window_registry,
|
||||
*env()->heap(), env()->ram_session_cap() };
|
||||
|
||||
Decorator_nitpicker_service decorator_nitpicker_service {
|
||||
ep, *env()->heap(), env()->ram_session_cap(), pointer_reporter,
|
||||
window_layouter_input, nitpicker_root };
|
||||
|
||||
Window_layouter_slave window_layouter_slave = {
|
||||
cap, *env()->ram_session(), window_list_rom, hover_rom,
|
||||
ep.manage(window_layouter_input), window_layout_report,
|
||||
resize_request_report, focus_report };
|
||||
|
||||
Decorator_slave decorator_slave = {
|
||||
cap, decorator_nitpicker_service, *env()->ram_session(),
|
||||
window_layout_rom, pointer_rom, hover_report };
|
||||
|
||||
Genode::Lazy_volatile_object<Attached_dataspace> focus_ds;
|
||||
|
||||
Nitpicker::Connection focus_nitpicker_session;
|
||||
|
||||
void handle_focus_update(unsigned)
|
||||
{
|
||||
try {
|
||||
if (!focus_ds.is_constructed() || focus_rom.update() == false)
|
||||
focus_ds.construct(focus_rom.dataspace());
|
||||
|
||||
unsigned long win_id = 0;
|
||||
|
||||
Xml_node(focus_ds->local_addr<char>()).sub_node("window")
|
||||
.attribute("id").value(&win_id);
|
||||
|
||||
if (win_id) {
|
||||
Nitpicker::Session_capability session_cap =
|
||||
nitpicker_root.lookup_nitpicker_session(win_id);
|
||||
|
||||
focus_nitpicker_session.focus(session_cap);
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
PWRN("no focus model available");
|
||||
}
|
||||
}
|
||||
|
||||
Genode::Signal_rpc_member<Main> focus_dispatcher = { ep, *this, &Main::handle_focus_update };
|
||||
|
||||
Genode::Lazy_volatile_object<Attached_dataspace> resize_request_ds;
|
||||
|
||||
void handle_resize_request_update(unsigned)
|
||||
{
|
||||
try {
|
||||
if (!resize_request_ds.is_constructed()
|
||||
|| resize_request_rom.update() == false)
|
||||
resize_request_ds.construct(resize_request_rom.dataspace());
|
||||
|
||||
char const * const node_type = "window";
|
||||
|
||||
Xml_node window =
|
||||
Xml_node(resize_request_ds->local_addr<char>()).sub_node(node_type);
|
||||
|
||||
for (;;) {
|
||||
unsigned long win_id = 0, width = 0, height = 0;
|
||||
|
||||
window.attribute("id") .value(&win_id);
|
||||
window.attribute("width") .value(&width);
|
||||
window.attribute("height").value(&height);
|
||||
|
||||
nitpicker_root.request_resize(win_id, Area(width, height));
|
||||
|
||||
if (window.is_last(node_type))
|
||||
break;
|
||||
|
||||
window = window.next(node_type);
|
||||
}
|
||||
|
||||
} catch (...) { /* no resize-request model available */ }
|
||||
}
|
||||
|
||||
Genode::Signal_rpc_member<Main> resize_request_dispatcher =
|
||||
{ ep, *this, &Main::handle_resize_request_update };
|
||||
|
||||
Main(Server::Entrypoint &ep) : ep(ep)
|
||||
{
|
||||
window_layouter_input.event_queue().enabled(true);
|
||||
|
||||
/* initially report an empty window list */
|
||||
Local_reporter::Xml_generator xml(window_list_reporter, [&] () { });
|
||||
|
||||
focus_rom.sigh(focus_dispatcher);
|
||||
resize_request_rom.sigh(resize_request_dispatcher);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/************
|
||||
** Server **
|
||||
************/
|
||||
|
||||
namespace Server {
|
||||
|
||||
char const *name() { return "desktop_ep"; }
|
||||
|
||||
size_t stack_size() { return 4*1024*sizeof(long); }
|
||||
|
||||
void construct(Entrypoint &ep)
|
||||
{
|
||||
static Wm::Main desktop(ep);
|
||||
}
|
||||
}
|
1005
repos/gems/src/server/wm/nitpicker.h
Normal file
1005
repos/gems/src/server/wm/nitpicker.h
Normal file
File diff suppressed because it is too large
Load Diff
173
repos/gems/src/server/wm/report_rom_slave.h
Normal file
173
repos/gems/src/server/wm/report_rom_slave.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* \brief Report-ROM slave
|
||||
* \author Norman Feske
|
||||
* \date 2014-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _REPORT_ROM_SLAVE_H_
|
||||
#define _REPORT_ROM_SLAVE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/lock.h>
|
||||
#include <os/slave.h>
|
||||
#include <report_session/report_session.h>
|
||||
#include <rom_session/capability.h>
|
||||
#include <root/client.h>
|
||||
|
||||
|
||||
class Report_rom_slave : public Genode::Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
class Policy : public Genode::Slave_policy
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Root_capability _report_root_cap;
|
||||
Genode::Root_capability _rom_root_cap;
|
||||
bool _announced;
|
||||
Genode::Lock mutable _lock; /* used to wait for announcement */
|
||||
|
||||
protected:
|
||||
|
||||
char const **_permitted_services() const
|
||||
{
|
||||
static char const *permitted_services[] = {
|
||||
"CAP", "LOG", "SIGNAL", "RM", 0 };
|
||||
|
||||
return permitted_services;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Policy(Genode::Rpc_entrypoint &entrypoint,
|
||||
Genode::Ram_session &ram)
|
||||
:
|
||||
Slave_policy("report_rom", entrypoint, &ram),
|
||||
_lock(Genode::Lock::LOCKED)
|
||||
{
|
||||
configure("<config> <rom>"
|
||||
" <policy label=\"window_list\" report=\"window_list\"/>"
|
||||
" <policy label=\"window_layout\" report=\"window_layout\"/>"
|
||||
" <policy label=\"resize_request\" report=\"resize_request\"/>"
|
||||
" <policy label=\"pointer\" report=\"pointer\"/>"
|
||||
" <policy label=\"hover\" report=\"hover\"/>"
|
||||
" <policy label=\"focus\" report=\"focus\"/>"
|
||||
"</rom> </config>");
|
||||
}
|
||||
|
||||
bool announce_service(const char *service_name,
|
||||
Genode::Root_capability root,
|
||||
Genode::Allocator *,
|
||||
Genode::Server *)
|
||||
{
|
||||
if (Genode::strcmp(service_name, "ROM") == 0)
|
||||
_rom_root_cap = root;
|
||||
else if (Genode::strcmp(service_name, "Report") == 0)
|
||||
_report_root_cap = root;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (_rom_root_cap.valid() && _report_root_cap.valid())
|
||||
_lock.unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Genode::Root_capability report_root() const
|
||||
{
|
||||
Genode::Lock::Guard guard(_lock);
|
||||
return _report_root_cap;
|
||||
}
|
||||
|
||||
Genode::Root_capability rom_root() const
|
||||
{
|
||||
Genode::Lock::Guard guard(_lock);
|
||||
return _rom_root_cap;
|
||||
}
|
||||
};
|
||||
|
||||
Genode::size_t const _ep_stack_size = 4*1024*sizeof(Genode::addr_t);
|
||||
Genode::Rpc_entrypoint _ep;
|
||||
Policy _policy;
|
||||
Genode::size_t const _quota = 1024*1024;
|
||||
Genode::Slave _slave;
|
||||
Genode::Root_client _rom_root;
|
||||
Genode::Root_client _report_root;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ep entrypoint used for nitpicker child thread
|
||||
* \param ram RAM session used to allocate the configuration
|
||||
* dataspace
|
||||
*/
|
||||
Report_rom_slave(Genode::Cap_session &cap, Genode::Ram_session &ram)
|
||||
:
|
||||
_ep(&cap, _ep_stack_size, "report_rom"),
|
||||
_policy(_ep, ram),
|
||||
_slave(_ep, _policy, _quota),
|
||||
_rom_root(_policy.rom_root()),
|
||||
_report_root(_policy.report_root())
|
||||
{ }
|
||||
|
||||
Genode::Rom_session_capability rom_session(char const *label)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
enum { ARGBUF_SIZE = 128 };
|
||||
char argbuf[ARGBUF_SIZE];
|
||||
argbuf[0] = 0;
|
||||
|
||||
/*
|
||||
* Declare ram-quota donation
|
||||
*/
|
||||
enum { SESSION_METADATA = 4*1024 };
|
||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", SESSION_METADATA);
|
||||
|
||||
/*
|
||||
* Set session label
|
||||
*/
|
||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "label", label);
|
||||
|
||||
Session_capability session_cap = _rom_root.session(argbuf, Affinity());
|
||||
|
||||
return static_cap_cast<Genode::Rom_session>(session_cap);
|
||||
}
|
||||
|
||||
Genode::Capability<Report::Session> report_session(char const *label)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
enum { ARGBUF_SIZE = 128 };
|
||||
char argbuf[ARGBUF_SIZE];
|
||||
argbuf[0] = 0;
|
||||
|
||||
/*
|
||||
* Declare ram-quota donation
|
||||
*/
|
||||
enum { BUFFER_SIZE = 4096, SESSION_METADATA = BUFFER_SIZE + 8*1024 };
|
||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", SESSION_METADATA);
|
||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "buffer_size", BUFFER_SIZE);
|
||||
|
||||
/*
|
||||
* Set session label
|
||||
*/
|
||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "label", label);
|
||||
|
||||
Session_capability session_cap = _report_root.session(argbuf, Affinity());
|
||||
|
||||
return static_cap_cast<Report::Session>(session_cap);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _REPORT_ROM_SLAVE_H_ */
|
41
repos/gems/src/server/wm/single_session_service.h
Normal file
41
repos/gems/src/server/wm/single_session_service.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* \brief Utility for implementing a local service with a single session
|
||||
* \author Norman Feske
|
||||
* \date 2014-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _SINGLE_SESSION_SERVICE_H_
|
||||
#define _SINGLE_SESSION_SERVICE_H_
|
||||
|
||||
#include <base/service.h>
|
||||
|
||||
namespace Wm { class Single_session_service; }
|
||||
|
||||
struct Wm::Single_session_service : Genode::Service
|
||||
{
|
||||
Genode::Session_capability session_cap;
|
||||
|
||||
Single_session_service(char const *service_name,
|
||||
Genode::Session_capability session_cap)
|
||||
:
|
||||
Service(service_name), session_cap(session_cap)
|
||||
{ }
|
||||
|
||||
Genode::Session_capability
|
||||
session(const char *, Genode::Affinity const &) override
|
||||
{
|
||||
return session_cap;
|
||||
}
|
||||
|
||||
void upgrade(Genode::Session_capability, const char *) override { }
|
||||
void close(Genode::Session_capability) override { }
|
||||
};
|
||||
|
||||
#endif /* _SINGLE_SESSION_SERVICE_H_ */
|
4
repos/gems/src/server/wm/target.mk
Normal file
4
repos/gems/src/server/wm/target.mk
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = wm
|
||||
SRC_CC = main.cc
|
||||
LIBS = base server config
|
||||
INC_DIR += $(PRG_DIR)
|
137
repos/gems/src/server/wm/window_layouter_slave.h
Normal file
137
repos/gems/src/server/wm/window_layouter_slave.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* \brief Slave for managing the window layout
|
||||
* \author Norman Feske
|
||||
* \date 2014-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _WINDOW_LAYOUTER_SLAVE_H_
|
||||
#define _WINDOW_LAYOUTER_SLAVE_H_
|
||||
|
||||
namespace Wm {
|
||||
|
||||
class Window_layouter_slave;
|
||||
|
||||
using Genode::Rom_session_capability;
|
||||
using Genode::Capability;
|
||||
}
|
||||
|
||||
|
||||
class Wm::Window_layouter_slave
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Ram_session &_ram;
|
||||
|
||||
class Policy : public Genode::Slave_policy
|
||||
{
|
||||
private:
|
||||
|
||||
Single_session_service _window_list_rom_service;
|
||||
Single_session_service _hover_rom_service;
|
||||
Single_session_service _input_service;
|
||||
Single_session_service _window_layout_report_service;
|
||||
Single_session_service _resize_request_report_service;
|
||||
Single_session_service _focus_report_service;
|
||||
|
||||
protected:
|
||||
|
||||
char const **_permitted_services() const
|
||||
{
|
||||
static char const *permitted_services[] = {
|
||||
"CAP", "LOG", "SIGNAL", "RM", "Timer", 0 };
|
||||
|
||||
return permitted_services;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Policy(Genode::Rpc_entrypoint &entrypoint,
|
||||
Genode::Ram_session &ram,
|
||||
Rom_session_capability window_list_rom,
|
||||
Rom_session_capability hover_rom,
|
||||
Input::Session_capability input,
|
||||
Capability<Report::Session> window_layout_report,
|
||||
Capability<Report::Session> resize_request_report,
|
||||
Capability<Report::Session> focus_report)
|
||||
:
|
||||
Slave_policy("floating_window_layouter", entrypoint, &ram),
|
||||
_window_list_rom_service("ROM", window_list_rom),
|
||||
_hover_rom_service("ROM", hover_rom),
|
||||
_input_service("Input", input),
|
||||
_window_layout_report_service("Report", window_layout_report),
|
||||
_resize_request_report_service("Report", resize_request_report),
|
||||
_focus_report_service("Report", focus_report)
|
||||
{ }
|
||||
|
||||
Genode::Service *resolve_session_request(const char *service_name,
|
||||
const char *args) override
|
||||
{
|
||||
using Genode::strcmp;
|
||||
|
||||
char label[128];
|
||||
Arg_string::find_arg(args, "label").string(label, sizeof(label), "");
|
||||
|
||||
if (strcmp(service_name, "ROM") == 0) {
|
||||
|
||||
if (strcmp(label, "floating_window_layouter -> window_list") == 0)
|
||||
return &_window_list_rom_service;
|
||||
|
||||
if (strcmp(label, "floating_window_layouter -> hover") == 0)
|
||||
return &_hover_rom_service;
|
||||
}
|
||||
|
||||
if (strcmp(service_name, "Report") == 0) {
|
||||
|
||||
if (strcmp(label, "floating_window_layouter -> window_layout") == 0)
|
||||
return &_window_layout_report_service;
|
||||
|
||||
if (strcmp(label, "floating_window_layouter -> resize_request") == 0)
|
||||
return &_resize_request_report_service;
|
||||
|
||||
if (strcmp(label, "floating_window_layouter -> focus") == 0)
|
||||
return &_focus_report_service;
|
||||
}
|
||||
|
||||
if (strcmp(service_name, "Input") == 0)
|
||||
return &_input_service;
|
||||
|
||||
return Genode::Slave_policy::resolve_session_request(service_name, args);
|
||||
}
|
||||
};
|
||||
|
||||
Genode::size_t const _ep_stack_size = 4*1024*sizeof(Genode::addr_t);
|
||||
Genode::Rpc_entrypoint _ep;
|
||||
Policy _policy;
|
||||
Genode::size_t const _quota = 1*1024*1024;
|
||||
Genode::Slave _slave;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Window_layouter_slave(Genode::Cap_session &cap,
|
||||
Genode::Ram_session &ram,
|
||||
Rom_session_capability window_list_rom,
|
||||
Rom_session_capability hover_rom,
|
||||
Input::Session_capability input,
|
||||
Capability<Report::Session> window_layout_report,
|
||||
Capability<Report::Session> resize_request_report,
|
||||
Capability<Report::Session> focus_report)
|
||||
:
|
||||
_ram(ram),
|
||||
_ep(&cap, _ep_stack_size, "floating_window_layouter"),
|
||||
_policy(_ep, ram, window_list_rom, hover_rom, input,
|
||||
window_layout_report, resize_request_report, focus_report),
|
||||
_slave(_ep, _policy, _quota)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _WINDOW_LAYOUTER_SLAVE_H_ */
|
188
repos/gems/src/server/wm/window_registry.h
Normal file
188
repos/gems/src/server/wm/window_registry.h
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* \brief Window registry
|
||||
* \author Norman Feske
|
||||
* \date 2014-05-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _WINDOW_REGISTRY_H_
|
||||
#define _WINDOW_REGISTRY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/bit_allocator.h>
|
||||
#include <util/list.h>
|
||||
#include <util/xml_generator.h>
|
||||
#include <base/allocator.h>
|
||||
#include <os/surface.h>
|
||||
|
||||
/* local includes */
|
||||
#include <local_reporter.h>
|
||||
|
||||
|
||||
namespace Wm { class Window_registry; }
|
||||
|
||||
|
||||
namespace Wm {
|
||||
using Genode::Allocator;
|
||||
using Genode::List;
|
||||
using Genode::Xml_generator;
|
||||
|
||||
typedef Genode::Surface_base::Area Area;
|
||||
typedef Genode::Surface_base::Point Point;
|
||||
typedef Genode::Surface_base::Rect Rect;
|
||||
}
|
||||
|
||||
|
||||
class Wm::Window_registry
|
||||
{
|
||||
public:
|
||||
|
||||
struct Id
|
||||
{
|
||||
unsigned value;
|
||||
|
||||
Id(unsigned value) : value(value) { }
|
||||
|
||||
Id() /* invalid */ : value(0) { }
|
||||
|
||||
bool operator == (Id const &other) const { return value == other.value; }
|
||||
|
||||
bool valid() const { return value != 0; }
|
||||
};
|
||||
|
||||
class Window : public List<Window>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Genode::String<200> Title;
|
||||
|
||||
private:
|
||||
|
||||
Id const _id;
|
||||
|
||||
Title _title;
|
||||
|
||||
Area _size;
|
||||
|
||||
friend class Window_registry;
|
||||
|
||||
Window(Id id) : _id(id) { }
|
||||
|
||||
public:
|
||||
|
||||
Id id() const { return _id; }
|
||||
|
||||
/*
|
||||
* Accessors for setting attributes
|
||||
*/
|
||||
void attr(Title const &title) { _title = title; }
|
||||
void attr(Area size) { _size = size; }
|
||||
|
||||
void generate_window_list_entry_xml(Xml_generator &xml) const
|
||||
{
|
||||
xml.node("window", [&] () {
|
||||
xml.attribute("id", _id.value);
|
||||
xml.attribute("title", _title.string());
|
||||
xml.attribute("width", _size.w());
|
||||
xml.attribute("height", _size.h());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Allocator &_alloc;
|
||||
Local_reporter &_window_list_reporter;
|
||||
|
||||
enum { MAX_WINDOWS = 1024 };
|
||||
|
||||
Genode::Bit_allocator<MAX_WINDOWS> _window_ids;
|
||||
|
||||
List<Window> _windows;
|
||||
|
||||
Window *_lookup(Id id)
|
||||
{
|
||||
for (Window *w = _windows.first(); w; w = w->next())
|
||||
if (w->id() == id)
|
||||
return w;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _report_updated_window_list_model() const
|
||||
{
|
||||
Local_reporter::Xml_generator xml(_window_list_reporter, [&] ()
|
||||
{
|
||||
for (Window const *w = _windows.first(); w; w = w->next())
|
||||
w->generate_window_list_entry_xml(xml);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ATTR>
|
||||
void _set_attr(Id const id, ATTR const &value)
|
||||
{
|
||||
Window * const win = _lookup(id);
|
||||
|
||||
if (!win) {
|
||||
PWRN("lookup for window ID %d failed", id.value);
|
||||
return;
|
||||
}
|
||||
|
||||
win->attr(value);
|
||||
|
||||
_report_updated_window_list_model();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Window_registry(Allocator &alloc, Local_reporter &window_list_reporter)
|
||||
:
|
||||
_alloc(alloc), _window_list_reporter(window_list_reporter)
|
||||
{
|
||||
/* preserve ID 0 to represent an invalid ID */
|
||||
_window_ids.alloc();
|
||||
}
|
||||
|
||||
Id create()
|
||||
{
|
||||
Window * const win = new (_alloc) Window(_window_ids.alloc());
|
||||
|
||||
_windows.insert(win);
|
||||
|
||||
/*
|
||||
* Even though we change the window-list model by adding a
|
||||
* window, we don't call '_report_updated_window_list_model' here
|
||||
* because the window does not have any useful properties before
|
||||
* the 'size' function has been called.
|
||||
*
|
||||
* XXX should we pass the initial size as argument to this function?
|
||||
*/
|
||||
|
||||
return win->id();
|
||||
}
|
||||
|
||||
void destroy(Id id)
|
||||
{
|
||||
Window * const win = _lookup(id);
|
||||
if (!win)
|
||||
return;
|
||||
|
||||
_windows.remove(win);
|
||||
|
||||
Genode::destroy(&_alloc, win);
|
||||
|
||||
_report_updated_window_list_model();
|
||||
}
|
||||
|
||||
void size(Id id, Area size) { _set_attr(id, size); }
|
||||
|
||||
void title(Id id, Window::Title title) { _set_attr(id, title); }
|
||||
};
|
||||
|
||||
#endif /* _WINDOW_REGISTRY_H_ */
|
Loading…
Reference in New Issue
Block a user