nitpicker: externalize xray policy

This patch removes the policy for controlling the X-Ray mode from
nitpicker to the separate component os/app/xray_trigger.

Fixes #1690
This commit is contained in:
Norman Feske 2015-09-30 11:30:02 +02:00 committed by Christian Helmuth
parent 2166aef737
commit 7c968d4c60
29 changed files with 687 additions and 541 deletions

View File

@ -14,10 +14,11 @@ set build_components {
app/trace_subject_reporter
app/cpu_load_display
app/cpu_burner
app/pointer
}
lappend_if [have_spec usb] build_components drivers/usb
lappend_if [have_spec gpio] build_components drivers/gpio
lappend_if [have_spec usb] build_components drivers/usb
lappend_if [have_spec gpio] build_components drivers/gpio
source ${genode_dir}/repos/base/run/platform_drv.inc
append_platform_drv_build_components
@ -100,14 +101,27 @@ append config {
<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="default" layer="2" />
<policy label="" domain="default"/>
<domain name="pointer" layer="1" label="no" content="client" origin="pointer" />
<domain name="default" layer="2" label="no" content="client" hover="always" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain="default"/>
</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="report_rom">
<resource name="RAM" quantum="4M"/>
<provides>
@ -121,6 +135,7 @@ append config {
</rom>
</config>
</start>
<start name="trace_subject_reporter" >
<resource name="RAM" quantum="6M"/>
<config period_ms="500">
@ -130,12 +145,14 @@ append config {
<any-service> <child name="report_rom"/> <any-child/> <parent/> </any-service>
</route>
</start>
<start name="cpu_load_display">
<resource name="RAM" quantum="6M"/>
<route>
<any-service> <child name="report_rom"/> <any-child/> <parent/> </any-service>
</route>
</start>
<start name="dynamic_rom">
<resource name="RAM" quantum="4M"/>
<provides><service name="ROM"/></provides>
@ -162,6 +179,7 @@ append config {
</rom>
</config>
</start>
<start name="cpu_burner.1">
<binary name="cpu_burner"/>
<resource name="RAM" quantum="1M"/>
@ -170,6 +188,7 @@ append config {
<any-service> <child name="dynamic_rom"/> <any-child/> <parent/> </any-service>
</route>
</start>
<start name="cpu_burner.2">
<binary name="cpu_burner"/>
<resource name="RAM" quantum="1M"/>
@ -195,7 +214,7 @@ foreach file { genode_logo.png grid.png } {
set boot_modules {
core init
timer
nitpicker report_rom dynamic_rom
nitpicker report_rom dynamic_rom pointer
cpu_load_display cpu_burner trace_subject_reporter
}

View File

@ -7,7 +7,7 @@ if {![have_spec linux]} {
}
set build_components {
core init drivers/timer drivers/framebuffer/sdl
core init drivers/timer drivers/framebuffer
server/dynamic_rom server/report_rom server/nitpicker app/decorator
}
@ -61,13 +61,8 @@ append config {
<provides><service name="Nitpicker"/></provides>
<config>
<report pointer="yes" />
<domain name="" layer="2" />
<domain name="" layer="2" content="client" label="no"/>
<policy label="" domain=""/>
<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="dynamic_rom">

View File

@ -102,7 +102,7 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<config>
<domain name="" layer="2" />
<domain name="" layer="2" content="client" label="no" />
<policy label="" domain=""/>
<report pointer="yes" />
</config>

View File

@ -7,7 +7,7 @@ if {![have_spec linux]} {
}
set build_components {
core init drivers/timer drivers/framebuffer/sdl
core init drivers/timer drivers/framebuffer
server/dynamic_rom server/nitpicker
app/pointer app/menu_view
app/scout
@ -52,17 +52,11 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<config>
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="" layer="3" />
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="" layer="3" content="client" label="no" hover="always" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
<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" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
</config>
</start>
<start name="pointer">

View File

@ -60,8 +60,8 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<config>
<domain name="" layer="2" />
<domain name="nano3d" layer="1" origin="pointer"/>
<domain name="" layer="2" content="client" label="no"/>
<domain name="nano3d" layer="1" content="client" label="no" origin="pointer"/>
<policy label="nano3d" domain="nano3d"/>
<policy label="" domain=""/>

View File

@ -7,7 +7,7 @@ if {![have_spec linux]} {
}
set build_components {
core init drivers/timer drivers/framebuffer/sdl
core init drivers/timer drivers/framebuffer
server/dynamic_rom server/nitpicker app/scout server/nit_fader
app/pointer
}
@ -51,17 +51,11 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<config>
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="" layer="3" />
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="" layer="3" content="client" label="no" focus="click" hover="always" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
<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" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
</config>
</start>
<start name="pointer">

View File

@ -62,21 +62,8 @@ append_if [have_spec sdl] config {
<service name="Framebuffer"/>
</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="" layer="2" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
</config>
<route>
<service name="Input"> <child name="fb_sdl"/> </service>
<service name="Framebuffer"> <child name="fb_sdl"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
<alias name="fb_drv" child="fb_sdl"/>
<alias name="input_drv" child="fb_sdl"/>}
append_platform_drv_config
@ -90,26 +77,25 @@ append_if [have_spec ps2] config {
<start name="ps2_drv">
<resource name="RAM" quantum="1M"/>
<provides><service name="Input"/></provides>
</start> }
</start>
<alias name="input_drv" child="ps2_drv"/>}
append_if [expr ! [have_spec sdl]] config {
append config {
<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="" layer="2" />
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="" layer="2" content="client" label="no" focus="click" hover="always" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
</config>
<route>
<service name="Input"> <child name="ps2_drv"/> </service>
<service name="Framebuffer"> <child name="fb_drv"/> </service>
<service name="Input"> <child name="input_drv"/> </service>
<service name="Framebuffer"> <child name="fb_drv"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
append config {
</start>
<start name="pointer">
<resource name="RAM" quantum="1M"/>
</start>

View File

@ -103,19 +103,11 @@ append config {
<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" />
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="default" layer="2" content="client" label="no" hover="always" focus="click" />
<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" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain="default"/>
</config>
</start>
<start name="pointer">

View File

@ -8,6 +8,8 @@ build {
lib/gallium
}
source ${genode_dir}/repos/base/run/platform_drv.inc
create_boot_directory
set config {
@ -62,8 +64,8 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<config>
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="" layer="2" />
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="" layer="2" content="client" focus="click" hover="always" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
</config>

View File

@ -70,19 +70,11 @@ proc qt5_start_nodes { feature_arg } {
<any-service> <parent /> <any-child /> </any-service>
</route>
<config>
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="decorator" layer="2" xray="opaque" />
<domain name="default" layer="2" />
<domain name="pointer" layer="1" label="no" content="client" origin="pointer" />
<domain name="default" layer="2" label="no" content="client" focus="click" hover="always" />
<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" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain="default"/>
</config>
</start>

View File

@ -10,15 +10,15 @@ if {[have_spec hw_odroid_xu]} {
set build_components {
core init
drivers/timer
server/nitpicker app/pointer app/status_bar
server/nitpicker app/pointer app/status_bar app/xray_trigger
server/liquid_framebuffer app/launchpad app/scout
test/nitpicker server/nitlog
drivers/framebuffer drivers/input
server/report_rom
server/report_rom server/rom_filter
}
lappend_if [have_spec usb] build_components drivers/usb
lappend_if [have_spec gpio] build_components drivers/gpio
lappend_if [have_spec usb] build_components drivers/usb
lappend_if [have_spec gpio] build_components drivers/gpio
source ${genode_dir}/repos/base/run/platform_drv.inc
append_platform_drv_build_components
@ -99,42 +99,108 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="report_rom">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config>
<rom>
<policy label="status_bar -> focus" report="nitpicker -> focus"/>
<policy label="status_bar -> focus" report="nitpicker -> focus"/>
<policy label="nitpicker_config -> xray" report="xray_trigger -> xray"/>
<policy label="xray_trigger -> hover" report="nitpicker -> hover"/>
</rom>
</config>
</start>
<start name="nitpicker">
<start name="nitpicker_config">
<binary name="rom_filter"/>
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<provides><service name="ROM"/></provides>
<config>
<report focus="yes" />
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="panel" layer="2" xray="no" />
<domain name="" layer="3" ypos="18" height="-18" />
<input name="xray_enabled" rom="xray" node="xray">
<attribute name="enabled" /> </input>
<policy label="pointer" domain="pointer"/>
<policy label="status_bar" domain="panel"/>
<policy label="" domain=""/>
<output node="config">
<inline>
<report focus="yes" xray="yes" hover="yes" />
<domain name="pointer" layer="1" origin="pointer"
content="client" label="no"/>
<domain name="panel" layer="2"
content="client" label="no" hover="always"/>
</inline>
<if>
<has_value input="xray_enabled" value="no" />
<then>
<inline>
<domain name="launchpad" layer="3"
content="client" label="no" hover="always" focus="click"
ypos="18" height="-18" />
<domain name="" layer="3"
content="client" label="no" hover="always" focus="click"
ypos="18" height="-18" />
</inline>
</then>
<else>
<inline>
<domain name="launchpad" layer="3" color="#dd0000"
content="tinted" label="yes" hover="focused" focus="click"
ypos="18" height="-18" />
<domain name="" layer="3" color="#55dd34"
content="tinted" label="yes" hover="focused" focus="click"
ypos="18" height="-18" />
</inline>
</else>
</if>
<inline>
<policy label="pointer" domain="pointer"/>
<policy label="status_bar" domain="panel"/>
<policy label="scout -> launchpad" domain="launchpad"/>
<policy label="" domain=""/>
<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" />
<global-key name="KEY_SCROLLLOCK" label="xray_trigger" />
<global-key name="KEY_F1" label="xray_trigger" />
<global-key name="KEY_F2" label="xray_trigger" />
</inline>
</output>
</config>
<route>
<service name="ROM"> <child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="xray_trigger">
<resource name="RAM" quantum="1M"/>
<config>
<press name="KEY_F1" xray="on"/>
<release name="KEY_F1" xray="off"/>
<press name="KEY_F2" xray="toggle"/>
<hover domain="panel"/>
</config>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<service name="ROM"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="nitpicker">
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<configfile name="nitpicker.config"/>
<route>
<service name="ROM" label="nitpicker.config">
<child name="nitpicker_config"/> </service>
<service name="Report">
<child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="pointer">
<resource name="RAM" quantum="1M"/>
</start>
<start name="status_bar">
<resource name="RAM" quantum="1M"/>
<route>
@ -142,6 +208,7 @@ append config {
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="scout">
<resource name="RAM" quantum="64M" />
</start>
@ -181,18 +248,18 @@ close $launchpad_config_fd
set boot_modules {
core init
timer
nitpicker pointer status_bar report_rom liquid_fb launchpad scout
testnit nitlog
nitpicker pointer status_bar report_rom rom_filter xray_trigger
liquid_fb launchpad scout testnit nitlog
launchpad.config
}
# platform-specific modules
lappend_if [have_spec linux] boot_modules fb_sdl
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 input_drv
lappend_if [have_spec linux] boot_modules fb_sdl
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 input_drv
append_platform_drv_boot_modules

View File

@ -0,0 +1,247 @@
/*
* \brief Policy for activating the X-Ray mode
* \author Norman Feske
* \date 2015-10-03
*/
/*
* Copyright (C) 2015 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/attached_rom_dataspace.h>
#include <nitpicker_session/connection.h>
#include <os/server.h>
#include <os/config.h>
#include <os/reporter.h>
#include <input/event.h>
#include <input/keycodes.h>
#include <timer_session/connection.h>
namespace Xray_trigger { struct Main; }
struct Xray_trigger::Main
{
Server::Entrypoint &_ep;
/**
* Nitpicker connection to obtain user input
*/
Nitpicker::Connection _nitpicker;
/**
* Input-event buffer
*/
Genode::Attached_dataspace _ev_ds { _nitpicker.input()->dataspace() };
/**
* Number of pressed keys, used to distinguish primary keys from key
* sequences.
*/
unsigned _key_cnt = 0;
/**
* Hover model as reported by nitpicker
*/
Genode::Lazy_volatile_object<Genode::Attached_rom_dataspace> _hover_ds;
/**
* Reporter for posting the result of our policy decision
*/
Genode::Reporter _xray_reporter { "xray" };
/**
* Timer to delay the xray report
*/
Timer::Connection _timer;
/**
* X-Ray criterion depending on key events
*/
bool _key_xray = false;
/**
* X-Ray criterion depending on hovered domain
*/
bool _hover_xray = false;
bool _xray() const { return _key_xray || _hover_xray; }
bool _evaluate_input(bool, unsigned, Input::Event const [], unsigned &) const;
bool _evaluate_hover(Genode::Xml_node) const;
/**
* Handler that is called on config changes, on hover-model changes, or on
* the arrival of user input
*/
void _handle_update(unsigned);
Genode::Signal_rpc_member<Main> _update_dispatcher =
{ _ep, *this, &Main::_handle_update };
void _report_xray()
{
Genode::Reporter::Xml_generator xml(_xray_reporter, [&] () {
xml.attribute("enabled", _xray() ? "yes" : "no");
});
}
/**
* Handler that is called after the xray report delay
*/
void _handle_timeout(unsigned)
{
_report_xray();
}
Genode::Signal_rpc_member<Main> _timeout_dispatcher =
{ _ep, *this, &Main::_handle_timeout };
Main(Server::Entrypoint &ep) : _ep(ep)
{
Genode::config()->sigh(_update_dispatcher);
_timer.sigh(_timeout_dispatcher);
/* enable xray reporter and produce initial xray report */
_xray_reporter.enabled(true);
_report_xray();
_nitpicker.input()->sigh(_update_dispatcher);
_handle_update(0);
}
};
bool Xray_trigger::Main::_evaluate_input(bool key_xray, unsigned num_ev,
Input::Event const events[],
unsigned &key_cnt) const
{
/* adjust '_key_xray' according to user key input */
for (unsigned i = 0; i < num_ev; i++) {
Input::Event const &ev = events[i];
if (ev.type() != Input::Event::PRESS
&& ev.type() != Input::Event::RELEASE)
continue;
if (ev.type() == Input::Event::PRESS) key_cnt++;
if (ev.type() == Input::Event::RELEASE) key_cnt--;
/* ignore key combinations */
if (key_cnt > 1) continue;
typedef Genode::String<32> Key_name;
Key_name const ev_key_name(Input::key_name(ev.keycode()));
typedef Genode::Xml_node Xml_node;
auto lambda = [&] (Xml_node node) {
if (!node.has_type("press") && !node.has_type("release"))
return;
if (node.has_type("press") && ev.type() != Input::Event::PRESS)
return;
if (node.has_type("release") && ev.type() != Input::Event::RELEASE)
return;
/*
* XML node applies for current event type, check if the key
* matches.
*/
Key_name const cfg_key_name =
node.attribute_value("name", Key_name());
if (cfg_key_name != ev_key_name)
return;
/*
* Manipulate X-Ray mode as instructed by the XML node.
*/
if (node.attribute("xray").has_value("on"))
key_xray = true;
if (node.attribute("xray").has_value("off"))
key_xray = false;
if (node.attribute("xray").has_value("toggle"))
key_xray = !_key_xray;
};
Genode::config()->xml_node().for_each_sub_node(lambda);
}
return key_xray;
}
bool Xray_trigger::Main::_evaluate_hover(Genode::Xml_node nitpicker_hover) const
{
bool hover_xray = false;
using namespace Genode;
config()->xml_node().for_each_sub_node("hover", [&] (Xml_node node) {
typedef String<160> Domain;
Domain nitpicker_domain = nitpicker_hover.attribute_value("domain", Domain());
Domain expected_domain = node.attribute_value("domain", Domain());
if (nitpicker_domain == expected_domain)
hover_xray = true;
});
return hover_xray;
}
void Xray_trigger::Main::_handle_update(unsigned)
{
Genode::config()->reload();
/* remember X-Ray mode prior applying the changes */
bool const orig_xray = _xray();
while (unsigned const num_ev = _nitpicker.input()->flush())
_key_xray = _evaluate_input(_key_xray, num_ev,
_ev_ds.local_addr<Input::Event const>(),
_key_cnt);
/* obtain / update hover model if needed */
if (Genode::config()->xml_node().has_sub_node("hover")) {
if (!_hover_ds.is_constructed()) {
_hover_ds.construct("hover");
_hover_ds->sigh(_update_dispatcher);
}
_hover_ds->update();
}
try {
_hover_xray = _evaluate_hover(Genode::Xml_node(_hover_ds->local_addr<char>(),
_hover_ds->size()));
} catch (...) { }
/* generate new X-Ray report if the X-Ray mode changed */
if (_xray() != orig_xray)
_timer.trigger_once(125000);
}
namespace Server {
char const *name() { return "ep"; }
size_t stack_size() { return 4*1024*sizeof(long); }
void construct(Entrypoint &ep) { static Xray_trigger::Main main(ep); }
}

View File

@ -0,0 +1,3 @@
TARGET = xray_trigger
SRC_CC = main.cc
LIBS += base server config

View File

@ -36,24 +36,26 @@ The properties of each domain are declared via '<domain>' nodes. For example:
! <config>
! ...
! <domain name="pointer" layer="1" xray="no" origin="pointer" />
! <domain name="panel" layer="2" xray="no" />
! <domain name="" layer="3" ypos="18" height="-18" />
! <domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
! <domain name="panel" layer="2" content="client" label="no" />
! <domain name="" layer="3" content="tinted" label="yes"
! focus="click" ypos="18" height="-18" />
! ...
! </config>
The 'name' attribute of a '<domain>' node corresponds to the 'domain'
declarations of the '<policy>' nodes.
Layering
--------
The 'name' attribute of a '<domain>' node corresponds to the 'domain'
declarations of the '<policy>' nodes. Each domain requires the definition
of a 'layer', which is number. It allows for constraining the stacking
position of the domain's views to a certain part of the global view stack.
The front-most layer has the number 0. In the example above, all views
of the "pointer" domain are presented in front of all others because the
"pointer" domain is assigned to the lowest layer. All views of the "panel"
domain are placed behind the "pointer" but in front to all other views
Each domain requires the definition of a 'layer', which is number. It allows
for constraining the stacking position of the domain's views to a certain part
of the global view stack. The front-most layer has the number 0. In the example
above, all views of the "pointer" domain are presented in front of all others
because the "pointer" domain is assigned to the lowest layer. All views of the
"panel" domain are placed behind the "pointer" but in front to all other views
that belong to the unnamed domain.
@ -100,56 +102,74 @@ value is subtracted from the physical dimensions. It is thereby possible to
shrink the reported screen size independent of the physical screen size.
X-Ray mode
----------
Input-focus policy
------------------
The behavior of nitpicker's X-ray mode can be defined for each domain
individually. Each domain can have an associated color configured via the
'color' attribute. This color is used by nitpicker when the X-ray mode
is active.
The 'focus' attribute denotes if and how nitpicker assigns the input focus
to sessions of the configured domain.
By setting the 'xray' attribute to "frame" (default), the views of the
domain will be surrounded by a thin frame of the domain color. The content
of all non-focussed views will be tinted using the domain color.
:"none": No session of the domain ever receives the focus.
When setting the 'xray' value to "opaque", the view's content will be
replaced by the opaque session color. This is useful for domains that
display many tiny views, e.g., window handles.
:"click": A session receives the focus when clicked with the mouse. After
the mouse button is released, the session keeps the focus.
By assigning the value "none", the X-ray mode will not be applied to the
domain. This is useful for trusted domains such as the pointer or a global
panel. When X-ray mode gets activated, the views of those trusted clients
remain unobstructed.
:"transient": A clicked session temporarily receives the input focus
while a mouse button is pressed. Upon the release of the mouse button,
the input focus is restored to the original session.
If not specified, the focus attribute defaults to 'none'.
Note that the input focus may also be manipulated via nitpicker's session
interface, which allows a client to yield the focus to other clients.
Hovering policy
---------------
By default, a client receives motion events only when in possession of the
input focus and when the pointer is located over one of the client's views.
However, certain clients such as a window decorator or a panel expect to
observe motion events referring to their part of the GUI regardless of the
current input focus. Otherwise, such a client cannot give visual feedback about
the currently hovered window control. To accommodate such clients, the 'hover'
domain attribute can be set to the value "always" instead of the default value
"focused".
Tinting and labeling of screen regions
--------------------------------------
Nitpicker is able to tint and label screen regions according to the clients
that are present on screen. The tinting and labeling assists the user to
uncover Trojan Horses, which are applications that mimic the appearance of
trusted applications to sneak credentials from the user. Both the tinting
and labeling are influenced by a color configured via the 'color' attribute of
the domain.
If the domain's 'label' attribute is set to "yes", each view of the domain is
surrounded by a frame painted with the domain color. Furthermore, the textual
label of the session is painted as watermark over the view content.
If the 'content' attribute is set to "tinted", the client-provided content
is mixed with the domain color unless the client has the input focus. If set
to "client", no tinting is performed. The latter is useful for trusted domains
such as the pointer or a global panel.
Global key definitions
~~~~~~~~~~~~~~~~~~~~~~
Nitpicker has a few built-in function that can be activated via global
keyboard shortcuts, namely the X-ray mode and the kill mode. The keys
for toggling those functions can be defined as follows:
! <config>
! ...
! <global-key name="KEY_SCROLLLOCK" operation="xray" />
! <global-key name="KEY_PRINT" operation="kill" />
! ...
! </config>
Each '<global-key>' node expresses a rule for a named key. The 'operation'
attribute refers nitpicker's built-in operations. In the example above, the
X-ray mode can be activated via the scroll-lock key and the kill mode can be
activated via the print key.
Alternatively to specifying an 'operation' attribute, a key node can contain
a 'label' attribute. If specified, all events regarding the key will be
reported to the client with the specified label. This enables clients to
handle global shortcuts. The client with the matching label will receive
all events until the number of concurrently pressed keys reaches zero.
This way, it is possible to handle chords of multiple keys starting with
the key specified in the '<key>' node. For the routing of global keys to
clients, the order of '<key>' nodes is important. If multiple nodes exists for
different labels, the first match will take effect. For example:
Nitpicker is able to direct global key sequences to dedicated clients using
'<global-key>' nodes. Such a node contains the key name of the initiating key
of the sequence as 'name' attribute and the designated receiver of the sequence
as 'label' attribute. If specified, all events belonging to the sequence will
be reported to the client with the specified label. This enables clients to
handle global shortcuts. The client with the matching label will receive all
events until the number of concurrently pressed keys reaches zero. This way, it
is possible to handle chords of multiple keys starting with the key specified
in the '<key>' node. For the routing of global keys to clients, the order of
'<key>' nodes is important. If multiple nodes exists for different labels, the
first match will take effect. For example:
! <config>
! ...

View File

@ -28,14 +28,10 @@ class Domain_registry
typedef Genode::String<64> Name;
typedef Genode::Color Color;
/**
* Behaviour of the views of the domain when X-ray is activated
*/
enum Xray {
XRAY_NO, /* views are not subjected to X-ray mode */
XRAY_FRAME, /* views are tinted and framed */
XRAY_OPAQUE, /* views are replaced by opaque domain color */
};
enum Label { LABEL_NO, LABEL_YES };
enum Content { CONTENT_CLIENT, CONTENT_TINTED };
enum Hover { HOVER_FOCUSED, HOVER_ALWAYS };
enum Focus { FOCUS_NONE, FOCUS_CLICK, FOCUS_TRANSIENT };
/**
* Origin of the domain's coordiate system
@ -49,21 +45,26 @@ class Domain_registry
private:
Name _name;
Color _color;
Xray _xray;
Origin _origin;
unsigned _layer;
Point _offset;
Point _area;
Name _name;
Color _color;
Label _label;
Content _content;
Hover _hover;
Focus _focus;
Origin _origin;
unsigned _layer;
Point _offset;
Point _area;
friend class Domain_registry;
Entry(Name const &name, Color color, Xray xray, Origin origin,
unsigned layer, Point offset, Point area)
Entry(Name const &name, Color color, Label label,
Content content, Hover hover, Focus focus,
Origin origin, unsigned layer, Point offset, Point area)
:
_name(name), _color(color), _xray(xray), _origin(origin),
_layer(layer), _offset(offset), _area(area)
_name(name), _color(color), _label(label),
_content(content), _hover(hover), _focus(focus),
_origin(origin), _layer(layer), _offset(offset), _area(area)
{ }
Point _corner(Area screen_area) const
@ -83,15 +84,19 @@ class Domain_registry
bool has_name(Name const &name) const { return name == _name; }
Name name() const { return _name; }
Name name() const { return _name; }
Color color() const { return _color; }
unsigned layer() const { return _layer; }
Content content() const { return _content; }
Hover hover() const { return _hover; }
Color color() const { return _color; }
unsigned layer() const { return _layer; }
bool xray_opaque() const { return _xray == XRAY_OPAQUE; }
bool xray_no() const { return _xray == XRAY_NO; }
bool origin_pointer() const { return _origin == ORIGIN_POINTER; }
bool label_visible() const { return _label == LABEL_YES; }
bool content_client() const { return _content == CONTENT_CLIENT; }
bool hover_focused() const { return _hover == HOVER_FOCUSED; }
bool hover_always() const { return _hover == HOVER_ALWAYS; }
bool focus_click() const { return _focus == FOCUS_CLICK; }
bool focus_transient() const { return _focus == FOCUS_TRANSIENT; }
bool origin_pointer() const { return _origin == ORIGIN_POINTER; }
Point phys_pos(Point pos, Area screen_area) const
{
@ -112,44 +117,67 @@ class Domain_registry
}
};
static Entry::Xray _xray(Genode::Xml_node domain)
static Entry::Label _label(Genode::Xml_node domain)
{
char const * const attr_name = "xray";
typedef Genode::String<32> Value;
Value const value = domain.attribute_value("label", Value("yes"));
Entry::Xray const default_xray = Entry::XRAY_FRAME;
if (value == "no") return Entry::LABEL_NO;
if (value == "yes") return Entry::LABEL_YES;
if (!domain.has_attribute(attr_name))
return default_xray;
Genode::Xml_node::Attribute const attr = domain.attribute(attr_name);
if (attr.has_value("no")) return Entry::XRAY_NO;
if (attr.has_value("frame")) return Entry::XRAY_FRAME;
if (attr.has_value("opaque")) return Entry::XRAY_OPAQUE;
PWRN("invalid value of xray attribute");
return default_xray;
PWRN("invalid value of label attribute in <domain>");
return Entry::LABEL_YES;
}
Entry::Origin _origin(Genode::Xml_node domain)
static Entry::Content _content(Genode::Xml_node domain)
{
char const * const attr_name = "origin";
typedef Genode::String<32> Value;
Value const value = domain.attribute_value("content", Value("tinted"));
Entry::Origin const default_origin = Entry::ORIGIN_TOP_LEFT;
if (value == "client") return Entry::CONTENT_CLIENT;
if (value == "tinted") return Entry::CONTENT_TINTED;
if (!domain.has_attribute(attr_name))
return default_origin;
return Entry::CONTENT_TINTED;
}
Genode::Xml_node::Attribute const attr = domain.attribute(attr_name);
static Entry::Hover _hover(Genode::Xml_node domain)
{
typedef Genode::String<32> Value;
Value const value = domain.attribute_value("hover", Value("focused"));
if (attr.has_value("top_left")) return Entry::ORIGIN_TOP_LEFT;
if (attr.has_value("top_right")) return Entry::ORIGIN_TOP_RIGHT;
if (attr.has_value("bottom_left")) return Entry::ORIGIN_BOTTOM_LEFT;
if (attr.has_value("bottom_right")) return Entry::ORIGIN_BOTTOM_RIGHT;
if (attr.has_value("pointer")) return Entry::ORIGIN_POINTER;
if (value == "focused") return Entry::HOVER_FOCUSED;
if (value == "always") return Entry::HOVER_ALWAYS;
PWRN("invalid value of origin attribute");
return default_origin;
PWRN("invalid value of hover attribute in <domain>");
return Entry::HOVER_FOCUSED;
}
static Entry::Focus _focus(Genode::Xml_node domain)
{
typedef Genode::String<32> Value;
Value const value = domain.attribute_value("focus", Value("none"));
if (value == "none") return Entry::FOCUS_NONE;
if (value == "click") return Entry::FOCUS_CLICK;
if (value == "transient") return Entry::FOCUS_TRANSIENT;
PWRN("invalid value of focus attribute in <domain>");
return Entry::FOCUS_NONE;
}
static Entry::Origin _origin(Genode::Xml_node domain)
{
typedef Genode::String<32> Value;
Value const value = domain.attribute_value("origin", Value("top_left"));
if (value == "top_left") return Entry::ORIGIN_TOP_LEFT;
if (value == "top_right") return Entry::ORIGIN_TOP_RIGHT;
if (value == "bottom_left") return Entry::ORIGIN_BOTTOM_LEFT;
if (value == "bottom_right") return Entry::ORIGIN_BOTTOM_RIGHT;
if (value == "pointer") return Entry::ORIGIN_POINTER;
PWRN("invalid value of origin attribute in <domain>");
return Entry::ORIGIN_BOTTOM_LEFT;
}
void _insert(Genode::Xml_node domain)
@ -189,7 +217,9 @@ class Domain_registry
Entry::Color const color = domain.attribute_value("color", WHITE);
_entries.insert(new (_alloc) Entry(name, color, _xray(domain),
_entries.insert(new (_alloc) Entry(name, color, _label(domain),
_content(domain), _hover(domain),
_focus(domain),
_origin(domain), layer, offset, area));
}

View File

@ -31,7 +31,7 @@ Global_keys::Policy *Global_keys::_lookup_policy(char const *key_name)
void Global_keys::apply_config(Session_list &session_list)
{
for (unsigned i = 0; i < NUM_POLICIES; i++)
_policies[i].undefine();
_policies[i] = Policy();
char const *node_type = "global-key";
@ -59,23 +59,6 @@ void Global_keys::apply_config(Session_list &session_list)
if (policy->defined())
continue;
if (node.has_attribute("operation")) {
Xml_node::Attribute operation = node.attribute("operation");
if (operation.has_value("kill")) {
policy->operation_kill();
continue;
} else if (operation.has_value("xray")) {
policy->operation_xray();
continue;
} else {
char buf[32]; buf[0] = 0;
operation.value(buf, sizeof(buf));
PWRN("unknown operation \"%s\" for key %s", buf, name);
}
continue;
}
if (!node.has_attribute("label")) {
PWRN("missing 'label' attribute for key %s", name);
continue;

View File

@ -26,42 +26,11 @@ class Global_keys
struct Policy
{
enum Type {
Session *_session = nullptr;
/**
* Key is not global but should be propagated to focused client
*/
UNDEFINED,
bool defined() const { return _session != nullptr; }
/**
* Key activates nitpicker's built-in kill mode
*/
KILL,
/**
* Key activates nitpicker's built-in X-ray mode
*/
XRAY,
/**
* Key should be propagated to client session
*/
CLIENT
};
Type _type;
Session *_session;
Policy() : _type(UNDEFINED), _session(0) { }
void undefine() { _type = UNDEFINED; _session = 0; }
void operation_kill() { _type = KILL; _session = 0; }
void operation_xray() { _type = XRAY; _session = 0; }
void client(Session *s) { _type = CLIENT; _session = s; }
bool defined() const { return _type != UNDEFINED; }
bool xray() const { return _type == XRAY; }
bool kill() const { return _type == KILL; }
void client(Session *s) { _session = s; }
};
enum { NUM_POLICIES = Input::KEY_MAX + 1 };
@ -82,15 +51,6 @@ class Global_keys
return _valid(key) ? _policies[key]._session : 0; }
void apply_config(Session_list &session_list);
bool is_operation_key(Input::Keycode key) const {
return _valid(key) && (_policies[key].xray() || _policies[key].kill()); }
bool is_xray_key(Input::Keycode key) const {
return _valid(key) && _policies[key].xray(); }
bool is_kill_key(Input::Keycode key) const {
return _valid(key) && _policies[key].kill(); }
};
#endif /* _GLOBAL_KEYS_H_ */

View File

@ -100,20 +100,6 @@ static void report_session(Genode::Reporter &reporter, Session *session,
}
static void report_kill_focus(Genode::Reporter &reporter)
{
if (!reporter.is_enabled())
return;
Genode::Reporter::Xml_generator xml(reporter, [&] ()
{
xml.attribute("label", "");
xml.attribute("domain", "");
xml.attribute("color", "#ff4444");
});
}
/*
* Font initialization
*/
@ -934,8 +920,11 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
};
_ep.apply(session_cap, lambda);
if (_mode.xray())
_view_stack.update_all_views();
/*
* XXX We may skip this if all domains are configured to show the
* raw client content.
*/
_view_stack.update_all_views();
}
void session_control(Label suffix, Session_control control) override
@ -1171,7 +1160,6 @@ struct Nitpicker::Main
Genode::Reporter pointer_reporter = { "pointer" };
Genode::Reporter hover_reporter = { "hover" };
Genode::Reporter focus_reporter = { "focus" };
Genode::Reporter xray_reporter = { "xray" };
Root<PT> np_root = { session_list, *domain_registry, global_keys,
ep.rpc_ep(), user_state, user_state, pointer_origin,
@ -1257,112 +1245,60 @@ void Nitpicker::Main::handle_input(unsigned)
{
period_cnt++;
/*
* If kill mode is already active, we got recursively called from
* within this 'input_func' (via 'wait_and_dispatch_one_signal').
* In this case, return immediately. New input events will be
* processed in the local 'do' loop.
*/
if (user_state.kill())
return;
Point const old_pointer_pos = user_state.pointer_pos();
::Session * const old_pointed_session = user_state.pointed_session();
::Session * const old_focused_session = user_state.Mode::focused_session();
bool const old_user_active = user_active;
do {
Point const old_pointer_pos = user_state.pointer_pos();
::Session * const old_pointed_session = user_state.pointed_session();
::Session * const old_focused_session = user_state.Mode::focused_session();
bool const old_kill_mode = user_state.kill();
bool const old_xray_mode = user_state.xray();
bool const old_user_active = user_active;
/* handle batch of pending events */
if (import_input_events(ev_buf, input.flush(), user_state)) {
last_active_period = period_cnt;
user_active = true;
}
/* handle batch of pending events */
if (import_input_events(ev_buf, input.flush(), user_state)) {
last_active_period = period_cnt;
user_active = true;
}
Point const new_pointer_pos = user_state.pointer_pos();
::Session * const new_pointed_session = user_state.pointed_session();
::Session * const new_focused_session = user_state.Mode::focused_session();
Point const new_pointer_pos = user_state.pointer_pos();
::Session * const new_pointed_session = user_state.pointed_session();
::Session * const new_focused_session = user_state.Mode::focused_session();
bool const new_kill_mode = user_state.kill();
bool const new_xray_mode = user_state.xray();
/* flag user as inactive after activity threshold is reached */
if (period_cnt == last_active_period + activity_threshold)
user_active = false;
/* flag user as inactive after activity threshold is reached */
if (period_cnt == last_active_period + activity_threshold)
user_active = false;
/* report mouse-position updates */
if (pointer_reporter.is_enabled() && old_pointer_pos != new_pointer_pos) {
/* report mouse-position updates */
if (pointer_reporter.is_enabled() && old_pointer_pos != new_pointer_pos) {
Genode::Reporter::Xml_generator xml(pointer_reporter, [&] ()
{
xml.attribute("xpos", new_pointer_pos.x());
xml.attribute("ypos", new_pointer_pos.y());
});
}
Genode::Reporter::Xml_generator xml(pointer_reporter, [&] ()
{
xml.attribute("xpos", new_pointer_pos.x());
xml.attribute("ypos", new_pointer_pos.y());
});
}
/* report hover changes */
if (!user_state.Mode::key_is_pressed()
&& old_pointed_session != new_pointed_session) {
report_session(hover_reporter, new_pointed_session);
}
if (xray_reporter.is_enabled() && old_xray_mode != new_xray_mode) {
/* report focus changes */
if (old_focused_session != new_focused_session
|| old_user_active != user_active)
report_session(focus_reporter, new_focused_session, user_active);
Genode::Reporter::Xml_generator xml(xray_reporter, [&] ()
{
xml.attribute("enabled", new_xray_mode ? "yes" : "no");
});
}
/* update mouse cursor */
if (old_pointer_pos != new_pointer_pos)
user_state.geometry(pointer_origin, Rect(new_pointer_pos, Area()));
/* report hover changes */
if (old_pointed_session != new_pointed_session)
report_session(hover_reporter, new_pointed_session);
/* perform redraw and flush pixels to the framebuffer */
user_state.draw(fb_screen->screen).flush([&] (Rect const &rect) {
framebuffer.refresh(rect.x1(), rect.y1(),
rect.w(), rect.h()); });
/* report focus changes */
if (old_focused_session != new_focused_session
|| old_user_active != user_active)
report_session(focus_reporter, new_focused_session, user_active);
user_state.mark_all_views_as_clean();
/* report kill mode */
if (old_kill_mode != new_kill_mode) {
if (new_kill_mode)
report_kill_focus(focus_reporter);
if (!new_kill_mode)
report_session(focus_reporter, new_focused_session);
}
/*
* Continuously redraw the whole screen when kill mode is active.
* Otherwise client updates (e.g., the status bar) would stay invisible
* because we do not dispatch the RPC interface during kill mode.
*/
if (new_kill_mode)
user_state.update_all_views();
/* update mouse cursor */
if (old_pointer_pos != new_pointer_pos)
user_state.geometry(pointer_origin, Rect(new_pointer_pos, Area()));
/* perform redraw and flush pixels to the framebuffer */
user_state.draw(fb_screen->screen).flush([&] (Rect const &rect) {
framebuffer.refresh(rect.x1(), rect.y1(),
rect.w(), rect.h()); });
user_state.mark_all_views_as_clean();
/* deliver framebuffer synchronization events */
if (!user_state.kill()) {
for (::Session *s = session_list.first(); s; s = s->next())
s->submit_sync();
}
/*
* In kill mode, we do not leave the dispatch function in order to
* block RPC calls from Nitpicker clients. We block for signals
* here to stay responsive to user input and configuration changes.
* Nested calls of 'input_func' are prevented by the condition
* check for 'user_state.kill()' at the beginning of the handler.
*/
if (user_state.kill())
Server::wait_and_dispatch_one_signal();
} while (user_state.kill());
/* deliver framebuffer synchronization events */
for (::Session *s = session_list.first(); s; s = s->next())
s->submit_sync();
}
@ -1405,7 +1341,6 @@ void Nitpicker::Main::handle_config(unsigned)
configure_reporter(pointer_reporter);
configure_reporter(hover_reporter);
configure_reporter(focus_reporter);
configure_reporter(xray_reporter);
/* update domain registry and session policies */
for (::Session *s = session_list.first(); s; s = s->next())

View File

@ -20,13 +20,9 @@ class Mode
{
private:
bool _xray = false;
bool _kill = false;
/*
* Number of currently pressed keys.
* This counter is used to determine if the user
* is dragging an item.
* Number of currently pressed keys. This counter is used to determine
* if the user is dragging an item.
*/
unsigned _key_cnt = 0;
@ -39,15 +35,8 @@ class Mode
/**
* Accessors
*/
bool xray() const { return _xray; }
bool kill() const { return _kill; }
bool flat() const { return !_xray && !_kill; }
bool drag() const { return _key_cnt > 0; }
void leave_kill() { _kill = false; }
void toggle_kill() { _kill = !_kill; }
void toggle_xray() { _xray = !_xray; }
void inc_key_cnt() { _key_cnt++; }
void dec_key_cnt() { _key_cnt--; }

View File

@ -75,10 +75,13 @@ class Session : public Session_list::Element
Genode::strlen(selector)) == 0;
}
bool xray_opaque() const { return _domain && _domain->xray_opaque(); }
bool xray_no() const { return _domain && _domain->xray_no(); }
/**
* Accessors to the domain configuration used in conditions
*/
bool label_visible() const { return !_domain || _domain->label_visible(); }
bool content_client() const { return _domain && _domain->content_client(); }
bool hover_focused() const { return !_domain || _domain->hover_focused(); }
bool hover_always() const { return _domain && _domain->hover_always(); }
bool origin_pointer() const { return _domain && _domain->origin_pointer(); }
unsigned layer() const { return _domain ? _domain->layer() : ~0UL; }
@ -166,6 +169,16 @@ class Session : public Session_list::Element
return s && (s->_domain == _domain);
}
bool has_click_focusable_domain()
{
return has_valid_domain() && _domain->focus_click();
}
bool has_transient_focusable_domain()
{
return has_valid_domain() && _domain->focus_transient();
}
bool has_valid_domain() const
{
return _domain;

View File

@ -23,10 +23,6 @@ using namespace Input;
** Utilities **
***************/
static inline bool _masked_key(Global_keys &global_keys, Keycode keycode) {
return global_keys.is_kill_key(keycode) || global_keys.is_xray_key(keycode); }
static inline bool _mouse_button(Keycode keycode) {
return keycode >= BTN_LEFT && keycode <= BTN_MIDDLE; }
@ -127,19 +123,7 @@ void User_state::handle_event(Input::Event ev)
*/
if (type == Event::PRESS && Mode::has_key_cnt(1)) {
/*
* Detect mouse press event in kill mode, used to select the session
* to lock out.
*/
if (kill() && keycode == Input::BTN_LEFT) {
if (_pointed_session)
lock_out_session(*_pointed_session);
/* leave kill mode */
update_all_guard.update = true;
Mode::leave_kill();
return;
}
::Session *global_receiver = nullptr;
/* update focused session */
if (pointed_session != Mode::focused_session() && _mouse_button(keycode)) {
@ -159,7 +143,10 @@ void User_state::handle_event(Input::Event ev)
pointed_session->submit_input_event(focus_ev);
}
focused_session(_pointed_session);
if (_pointed_session->has_transient_focusable_domain())
global_receiver = _pointed_session;
else if (_pointed_session->has_click_focusable_domain())
focused_session(_pointed_session);
}
/*
@ -172,7 +159,9 @@ void User_state::handle_event(Input::Event ev)
* to the global receiver. To reflect that change, we need to update
* the whole screen.
*/
::Session * const global_receiver = _global_keys.global_receiver(keycode);
if (!global_receiver)
global_receiver = _global_keys.global_receiver(keycode);
if (global_receiver) {
_global_key_sequence = true;
_input_receiver = global_receiver;
@ -186,53 +175,37 @@ void User_state::handle_event(Input::Event ev)
if (!global_receiver) {
_input_receiver = Mode::focused_session();
}
/*
* Toggle kill and xray modes. If one of those keys is pressed,
* suppress the delivery to clients.
*/
if (_global_keys.is_operation_key(keycode)) {
if (_global_keys.is_kill_key(keycode)) {
Mode::toggle_kill();
_input_receiver = 0;
}
if (_global_keys.is_xray_key(keycode)) Mode::toggle_xray();
update_all_guard.update = true;
}
}
/*
* Deliver event to session except when kill mode is activated
* Deliver event to session
*/
if (kill()) return;
if (type == Event::MOTION || type == Event::WHEEL || type == Event::TOUCH) {
if (Mode::has_key_cnt(0)) {
/*
* In flat mode, we deliver motion events to the pointed-at
* session. In xray mode, we deliver motion events only to the
* focused session.
*/
if (flat() || (xray() && Mode::focused_session() == pointed_session)
|| (pointed_session && pointed_session->xray_no()))
if (pointed_session)
if (pointed_session) {
/*
* Unless the domain of the pointed session is configured to
* always receive hover events, we deliver motion events only
* to the focused domain.
*/
if (pointed_session->hover_always()
|| pointed_session->has_same_domain(Mode::focused_session()))
pointed_session->submit_input_event(ev);
}
} else if (_input_receiver)
_input_receiver->submit_input_event(ev);
}
/*
* Deliver press/release event to focused session. Never deliver events
* for keys that are configured for global operations.
* Deliver press/release event to focused session or the receiver of global
* key.
*/
if (type == Event::PRESS || type == Event::RELEASE)
if (_input_receiver && !_global_keys.is_operation_key(keycode))
if (_input_receiver)
_input_receiver->submit_input_event(ev);
/*

View File

@ -70,21 +70,11 @@ void View::title(const char *title)
void View::frame(Canvas_base &canvas, Mode const &mode) const
{
/* do not draw frame in flat mode */
if (mode.flat()) return;
if (!_session.label_visible())
return;
Rect const geometry = abs_geometry();
if (_session.xray_no())
return;
if (_session.xray_opaque()) {
Point frame_offset(frame_size(mode), frame_size(mode));
Rect rect(geometry.p1() - frame_offset, geometry.p2() + frame_offset);
canvas.draw_box(rect, _session.color());
return;
}
draw_frame(canvas, geometry, _session.color(), frame_size(mode));
}
@ -95,13 +85,11 @@ void View::frame(Canvas_base &canvas, Mode const &mode) const
static Texture_painter::Mode
texture_painter_mode(Mode const &mode, Session const &session)
{
bool const is_focused = session.has_same_domain(mode.focused_session());
/*
* Use dimming in x-ray and kill mode, but do not dim the focused view in
* x-ray mode.
* Tint view unless it belongs to a domain that is explicitly configured to
* display the raw client content or if belongs to the focused domain.
*/
if (mode.flat() || (session.xray_no()) || (mode.xray() && is_focused))
if (session.content_client() || session.has_same_domain(mode.focused_session()))
return Texture_painter::SOLID;
return Texture_painter::MIXED;
@ -135,28 +123,22 @@ void View::draw(Canvas_base &canvas, Mode const &mode) const
}
}
/* allow alpha blending only in flat mode */
bool allow_alpha = mode.flat() || _session.xray_no();
/* allow alpha blending only if the raw client content is enabled */
bool allow_alpha = _session.content_client();
/* draw view content */
Color const mix_color = mode.kill() ? KILL_COLOR
: Color(_session.color().r >> 1,
Color const mix_color = Color(_session.color().r >> 1,
_session.color().g >> 1,
_session.color().b >> 1);
if (mode.xray() && _session.xray_opaque()) {
canvas.draw_box(view_rect, _session.color());
if (_session.texture()) {
canvas.draw_texture(_buffer_off + view_rect.p1(), *_session.texture(),
op, mix_color, allow_alpha);
} else {
if (_session.texture()) {
canvas.draw_texture(_buffer_off + view_rect.p1(), *_session.texture(),
op, mix_color, allow_alpha);
} else {
canvas.draw_box(view_rect, BLACK);
}
canvas.draw_box(view_rect, BLACK);
}
if (mode.flat() || _session.xray_opaque() || _session.xray_no()) return;
if (!_session.label_visible()) return;
/* draw label */
Color const frame_color = _session.color();

View File

@ -204,8 +204,7 @@ class View : public Same_buffer_list_elem,
*/
virtual int frame_size(Mode const &mode) const
{
if (_session.xray_opaque()) return 1;
if (_session.xray_no()) return 0;
if (!_session.label_visible()) return 0;
return mode.is_focused(_session) ? 5 : 3;
}
@ -276,7 +275,7 @@ class View : public Same_buffer_list_elem,
return false;
/* if view uses an alpha channel, check the input mask */
if ((mode.flat() || _session.xray_no()) && session().uses_alpha())
if (_session.content_client() && session().uses_alpha())
return session().input_mask_at(p - view_rect.p1() - _buffer_off);
return true;

View File

@ -51,8 +51,6 @@ Rect View_stack::_outline(View const &view) const
{
Rect const rect = view.abs_geometry();
if (_mode.flat()) return rect;
/* request thickness of view frame */
int const frame_size = view.frame_size(_mode);
@ -135,8 +133,9 @@ void View_stack::_optimize_label_rec(View const *cv, View const *lv, Rect rect,
void View_stack::_place_labels(Rect rect)
{
/* do not calculate label positions in flat mode */
if (_mode.flat()) return;
/*
* XXX We may skip this if none of the domains have the labeling enabled.
*/
/* ignore mouse cursor */
View const *start = _next_view(*_first_view());

View File

@ -241,22 +241,6 @@ class View_stack
*/
bool is_default_background(View const &view) const { return &view == _default_background; }
/**
* Remove all views of specified session from view stack
*
* Rather than removing the views from the view stack, this function moves
* the session views out of the visible screen area.
*/
void lock_out_session(Session const &session)
{
View const *view = _first_view(), *next_view = view->view_stack_next();
while (view) {
if (view->belongs_to(session)) remove_view(*view);
view = next_view;
next_view = view ? view->view_stack_next() : 0;
}
}
void apply_origin_policy(View &pointer_origin)
{
for (View *v = _first_view(); v; v = v->view_stack_next())

View File

@ -90,8 +90,8 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<config>
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="" layer="2" />
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="" layer="2" content="client" focus="click" />
<policy label="pointer" domain="pointer"/>
<policy label="" domain=""/>
</config>

View File

@ -290,23 +290,18 @@ append_if $use_fancy_stuff config {
<resource name="RAM" quantum="8M"/>
<config>
<report focus="yes" />
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="panel" layer="2" xray="no" />
<domain name="" layer="3" ypos="18" height="-18" />
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="panel" layer="2" content="client" label="no" focus="none" />
<domain name="" layer="3" content="client" focus="click"
hover="always" ypos="18" height="-18" />
<policy label="pointer" domain="pointer"/>
<policy label="status_bar" domain="panel"/>
<policy label="" domain=""/>
<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>
<route>
<service name="Timer"> <child name="timer"/></service>
<service name="Framebuffer"><child name="fb_drv"/></service>
<service name="Report"> <child name="report_rom"/></service>
<any-service><parent/><any-child/></any-service>
</route>
<provides><service name="Nitpicker"/></provides>

View File

@ -9,7 +9,7 @@ assert_spec linux
set build_components {
core init
drivers/timer
drivers/framebuffer/sdl
drivers/framebuffer
server/report_rom
server/dynamic_rom
server/nitpicker
@ -94,15 +94,14 @@ set config {
<provides><service name="Nitpicker"/></provides>
<config>
<report focus="yes" hover="yes" xray="yes"/>
<domain name="pointer" layer="1" xray="no" origin="pointer"/>
<domain name="smiley" layer="3"/>
<domain name="" layer="3"/>
<domain name="pointer" layer="1" content="client" label="no" origin="pointer"/>
<domain name="smiley" layer="3" content="client" label="no"/>
<domain name="" layer="3" content="client" label="no"/>
<policy label="pointer" domain="pointer"/>
<policy label="test-domain-smiley" domain="smiley"/>
<policy label="" domain=""/>
<global-key name="KEY_F12" operation="xray"/>
<background color="#00426f"/> <!-- indigo -->
</config>
<route>

View File

@ -112,19 +112,13 @@ append config_of_app {
<config>
<report focus="yes" hover="yes" xray="yes" />
<domain name="pointer" layer="1" xray="no" origin="pointer" />
<domain name="vbox" layer="2" />
<domain name="" layer="2" />
<domain name="pointer" layer="1" content="origin" label="no" origin="pointer" />
<domain name="vbox" layer="2" content="origin" focus="click" hover="always" />
<domain name="" layer="2" content="origin" focus="click" hover="always" />
<policy label="vbox_pointer" domain="pointer"/>
<policy label="nit_fb" domain="vbox"/>
<policy label="" domain=""/>
<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>