diff --git a/repos/gems/run/cpu_load_display.run b/repos/gems/run/cpu_load_display.run index 6c2e1d121..50dd7a8d3 100644 --- a/repos/gems/run/cpu_load_display.run +++ b/repos/gems/run/cpu_load_display.run @@ -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 { + - - + + + + + + + + + + + + + + @@ -121,6 +135,7 @@ append config { + @@ -130,12 +145,14 @@ append config { + + @@ -162,6 +179,7 @@ append config { + @@ -170,6 +188,7 @@ append config { + @@ -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 } diff --git a/repos/gems/run/decorator.run b/repos/gems/run/decorator.run index 90b3eb903..9ba60e324 100644 --- a/repos/gems/run/decorator.run +++ b/repos/gems/run/decorator.run @@ -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 { - + - - - - - diff --git a/repos/gems/run/decorator_stress.run b/repos/gems/run/decorator_stress.run index d22300b95..3fe5fa48c 100644 --- a/repos/gems/run/decorator_stress.run +++ b/repos/gems/run/decorator_stress.run @@ -102,7 +102,7 @@ append config { - + diff --git a/repos/gems/run/menu_view.run b/repos/gems/run/menu_view.run index 8e9dca05b..2a0177bc8 100644 --- a/repos/gems/run/menu_view.run +++ b/repos/gems/run/menu_view.run @@ -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 { - - + + - - - - - - - - + + diff --git a/repos/gems/run/nano3d.run b/repos/gems/run/nano3d.run index ef4fcd47c..9a57b6e55 100644 --- a/repos/gems/run/nano3d.run +++ b/repos/gems/run/nano3d.run @@ -60,8 +60,8 @@ append config { - - + + diff --git a/repos/gems/run/nit_fader.run b/repos/gems/run/nit_fader.run index 01bc1330a..be59896bc 100644 --- a/repos/gems/run/nit_fader.run +++ b/repos/gems/run/nit_fader.run @@ -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 { - - + + - - - - - - - - + + diff --git a/repos/gems/run/terminal_log.run b/repos/gems/run/terminal_log.run index 70824feac..dcc1d3b4a 100644 --- a/repos/gems/run/terminal_log.run +++ b/repos/gems/run/terminal_log.run @@ -62,21 +62,8 @@ append_if [have_spec sdl] config { - - - - - - - - - - - - - - - } + + } append_platform_drv_config @@ -90,26 +77,25 @@ append_if [have_spec ps2] config { - } + + } -append_if [expr ! [have_spec sdl]] config { +append config { - - + + - - + + - } - -append config { + diff --git a/repos/gems/run/wm.run b/repos/gems/run/wm.run index bb3dc4787..4b9828089 100644 --- a/repos/gems/run/wm.run +++ b/repos/gems/run/wm.run @@ -103,19 +103,11 @@ append config { - - - + + - - - - - - - - - + + diff --git a/repos/libports/run/eglgears.run b/repos/libports/run/eglgears.run index d92dd1b76..e75e530da 100644 --- a/repos/libports/run/eglgears.run +++ b/repos/libports/run/eglgears.run @@ -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 { - - + + diff --git a/repos/libports/run/qt5_common.inc b/repos/libports/run/qt5_common.inc index 9335f98f5..b9d225b2f 100644 --- a/repos/libports/run/qt5_common.inc +++ b/repos/libports/run/qt5_common.inc @@ -70,19 +70,11 @@ proc qt5_start_nodes { feature_arg } { - - - + + - - - - - - - - - + + diff --git a/repos/os/run/demo.run b/repos/os/run/demo.run index b0150e927..bc9ea628e 100644 --- a/repos/os/run/demo.run +++ b/repos/os/run/demo.run @@ -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 { + - + + + - + + + - + - - - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -142,6 +208,7 @@ append config { + @@ -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 diff --git a/repos/os/src/app/xray_trigger/main.cc b/repos/os/src/app/xray_trigger/main.cc new file mode 100644 index 000000000..89ff7e064 --- /dev/null +++ b/repos/os/src/app/xray_trigger/main.cc @@ -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 +#include +#include +#include +#include +#include +#include +#include + + +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 _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
_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
_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(), + _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(), + _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); } +} diff --git a/repos/os/src/app/xray_trigger/target.mk b/repos/os/src/app/xray_trigger/target.mk new file mode 100644 index 000000000..1d5d09ffb --- /dev/null +++ b/repos/os/src/app/xray_trigger/target.mk @@ -0,0 +1,3 @@ +TARGET = xray_trigger +SRC_CC = main.cc +LIBS += base server config diff --git a/repos/os/src/server/nitpicker/README b/repos/os/src/server/nitpicker/README index f2b6b7619..cb07c4825 100644 --- a/repos/os/src/server/nitpicker/README +++ b/repos/os/src/server/nitpicker/README @@ -36,24 +36,26 @@ The properties of each domain are declared via '' nodes. For example: ! ! ... -! -! -! +! +! +! ! ... ! +The 'name' attribute of a '' node corresponds to the 'domain' +declarations of the '' nodes. + Layering -------- -The 'name' attribute of a '' node corresponds to the 'domain' -declarations of the '' 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: - -! -! ... -! -! -! ... -! - -Each '' 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 '' node. For the routing of global keys to -clients, the order of '' 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 +'' 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 '' node. For the routing of global keys to clients, the order of +'' nodes is important. If multiple nodes exists for different labels, the +first match will take effect. For example: ! ! ... diff --git a/repos/os/src/server/nitpicker/domain_registry.h b/repos/os/src/server/nitpicker/domain_registry.h index b2347771e..2871b9c48 100644 --- a/repos/os/src/server/nitpicker/domain_registry.h +++ b/repos/os/src/server/nitpicker/domain_registry.h @@ -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 "); + 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 "); + 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 "); + 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 "); + 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)); } diff --git a/repos/os/src/server/nitpicker/global_keys.cc b/repos/os/src/server/nitpicker/global_keys.cc index 2d4b69c11..03badfaa0 100644 --- a/repos/os/src/server/nitpicker/global_keys.cc +++ b/repos/os/src/server/nitpicker/global_keys.cc @@ -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; diff --git a/repos/os/src/server/nitpicker/global_keys.h b/repos/os/src/server/nitpicker/global_keys.h index 038e73d7d..a8302a42f 100644 --- a/repos/os/src/server/nitpicker/global_keys.h +++ b/repos/os/src/server/nitpicker/global_keys.h @@ -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_ */ diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 41afcd9f1..3846d249b 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -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, }; _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 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()) diff --git a/repos/os/src/server/nitpicker/mode.h b/repos/os/src/server/nitpicker/mode.h index 6ad38893e..dce0ec0aa 100644 --- a/repos/os/src/server/nitpicker/mode.h +++ b/repos/os/src/server/nitpicker/mode.h @@ -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--; } diff --git a/repos/os/src/server/nitpicker/session.h b/repos/os/src/server/nitpicker/session.h index 8b79a27e1..1db716abd 100644 --- a/repos/os/src/server/nitpicker/session.h +++ b/repos/os/src/server/nitpicker/session.h @@ -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; diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index dfdf0d96f..c08e96cc0 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -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); /* diff --git a/repos/os/src/server/nitpicker/view.cc b/repos/os/src/server/nitpicker/view.cc index d0f210c8d..aab4fd41f 100644 --- a/repos/os/src/server/nitpicker/view.cc +++ b/repos/os/src/server/nitpicker/view.cc @@ -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(); diff --git a/repos/os/src/server/nitpicker/view.h b/repos/os/src/server/nitpicker/view.h index 9a0108c5a..95602b748 100644 --- a/repos/os/src/server/nitpicker/view.h +++ b/repos/os/src/server/nitpicker/view.h @@ -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; diff --git a/repos/os/src/server/nitpicker/view_stack.cc b/repos/os/src/server/nitpicker/view_stack.cc index 22eb85744..f803de9a5 100644 --- a/repos/os/src/server/nitpicker/view_stack.cc +++ b/repos/os/src/server/nitpicker/view_stack.cc @@ -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()); diff --git a/repos/os/src/server/nitpicker/view_stack.h b/repos/os/src/server/nitpicker/view_stack.h index f8dde55b8..fc8807340 100644 --- a/repos/os/src/server/nitpicker/view_stack.h +++ b/repos/os/src/server/nitpicker/view_stack.h @@ -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()) diff --git a/repos/ports/run/noux_terminal_fs.run b/repos/ports/run/noux_terminal_fs.run index e8a6f7010..82429cd3e 100644 --- a/repos/ports/run/noux_terminal_fs.run +++ b/repos/ports/run/noux_terminal_fs.run @@ -90,8 +90,8 @@ append config { - - + + diff --git a/repos/ports/run/seoul.inc b/repos/ports/run/seoul.inc index 4ec85a79e..395dd701b 100644 --- a/repos/ports/run/seoul.inc +++ b/repos/ports/run/seoul.inc @@ -290,23 +290,18 @@ append_if $use_fancy_stuff config { - - - - + + + - - - - - - + diff --git a/repos/ports/run/vbox_pointer.run b/repos/ports/run/vbox_pointer.run index 3a442c6fa..e64a75758 100644 --- a/repos/ports/run/vbox_pointer.run +++ b/repos/ports/run/vbox_pointer.run @@ -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 { - - - + + + - diff --git a/repos/ports/run/vbox_win.inc b/repos/ports/run/vbox_win.inc index 51c122885..0809054f7 100644 --- a/repos/ports/run/vbox_win.inc +++ b/repos/ports/run/vbox_win.inc @@ -112,19 +112,13 @@ append config_of_app { - - - + + + - - - - - -