diff --git a/src/netxs/apps.hpp b/src/netxs/apps.hpp index 10f7b115a3..90c7208782 100644 --- a/src/netxs/apps.hpp +++ b/src/netxs/apps.hpp @@ -388,12 +388,14 @@ namespace netxs::app::shared auto window = ui::veer::ctor() ->limits(dot_11) ->plugin(); - auto term = ui::cake::ctor() + auto term_cake = ui::cake::ctor() ->active(window_clr); - auto dtvt = ui::dtvt::ctor(); - auto scrl = term->attach(ui::rail::ctor()); + auto dtvt = ui::dtvt::ctor() + ->plugin(pro::focus::mode::relay, faux/*default: don't cut_scope*/, faux/*no default focus*/) + ->limits(dot_11); + auto scrl = term_cake->attach(ui::rail::ctor()); auto defclr = config.take("/config/terminal/colors/default", cell{}.fgc(whitelt).bgc(blackdk)); - auto inst = scrl->attach(ui::term::ctor(config)) + auto term = scrl->attach(ui::term::ctor(config)) ->plugin(pro::focus::mode::focused) ->colors(defclr.fgc(), defclr.bgc()) ->invoke([&](auto& boss) @@ -418,12 +420,10 @@ namespace netxs::app::shared dtvt_inst.stop(fast, faux); }; }); - term->attach(app::shared::scroll_bars(scrl)); - dtvt->plugin(pro::focus::mode::relay) - ->limits(dot_11) - ->invoke([&](auto& boss) + term_cake->attach(app::shared::scroll_bars(scrl)); + dtvt->invoke([&](auto& boss) { - auto& term_inst = *inst; + auto& term_inst = *term; boss.LISTEN(tier::preview, e2::config::plugins::sizer::alive, state) { boss.base::riseup(tier::release, e2::config::plugins::sizer::alive, state); @@ -442,11 +442,11 @@ namespace netxs::app::shared }; }); window->branch(dtvt) - ->branch(term) + ->branch(term_cake) ->invoke([&](auto& boss) { auto& dtvt_inst = *dtvt; - auto& term_inst = *inst; + auto& term_inst = *term; boss.LISTEN(tier::release, e2::form::upon::started, root, -, (appcfg)) { if (root) // root is empty when d_n_d. @@ -466,11 +466,8 @@ namespace netxs::app::shared { if (!!started == order) { - auto t = term_inst.This(); - auto d = dtvt_inst.This(); - if (order) pro::focus::pass(t, d); - else pro::focus::pass(d, t); boss.roll(); + boss.bell::signal(tier::request, hids::events::focus::hop, { .item = boss.back() }); boss.back()->base::riseup(tier::preview, e2::form::prop::ui::footer); boss.back()->reflow(); boss.back()->deface(); diff --git a/src/netxs/apps/term.hpp b/src/netxs/apps/term.hpp index f2504f6271..42e587f64a 100644 --- a/src/netxs/apps/term.hpp +++ b/src/netxs/apps/term.hpp @@ -767,7 +767,7 @@ namespace netxs::app::terminal auto scroll = layers->attach(ui::rail::ctor()) ->limits({ 10,1 }); // mc crashes when window is too small if (appcfg.cmd.empty()) appcfg.cmd = os::env::shell();//todo revise + " -i"; - auto inst = scroll->attach(ui::term::ctor(config)) + auto term = scroll->attach(ui::term::ctor(config)) ->plugin(pro::focus::mode::focused) ->colors(defclr.fgc(), defclr.bgc()) ->invoke([&](auto& boss) @@ -892,7 +892,7 @@ namespace netxs::app::terminal }); if (appcfg.cmd.empty()) appcfg.cmd = os::env::shell();//todo revise + " -i"; - auto inst = scroll->attach(ui::term::ctor(config)) + auto term = scroll->attach(ui::term::ctor(config)) ->plugin(pro::focus::mode::focused) ->invoke([&](auto& boss) { @@ -970,8 +970,8 @@ namespace netxs::app::terminal ->limits({ -1,1 }, { -1,1 }) ->invoke([&](auto& boss) { - boss.color(boss.color().bgc(inst->color().bgc())); - inst->LISTEN(tier::release, e2::form::prop::filler, brush, -) + boss.color(boss.color().bgc(term->color().bgc())); + term->LISTEN(tier::release, e2::form::prop::filler, brush, -) { boss.color(boss.color().bgc(brush.bgc())); }; @@ -990,7 +990,7 @@ namespace netxs::app::terminal cover->invoke([&, &slot1 = slot1](auto& boss) //todo clang 15.0.0 still disallows capturing structured bindings (wait for clang 16.0.0) { auto bar = cell{ "▀"sv }.link(slot1->id); - auto term_bgc_ptr = ptr::shared(inst->color().bgc()); + auto term_bgc_ptr = ptr::shared(term->color().bgc()); auto& term_bgc = *term_bgc_ptr; auto winsz = ptr::shared(dot_00); auto visible = ptr::shared(slot1->back() != boss.This()); @@ -1011,7 +1011,7 @@ namespace netxs::app::terminal *winsz = new_area.size; (*check_state)(boss); }; - inst->LISTEN(tier::release, e2::form::prop::filler, clr, -, (term_bgc_ptr)) + term->LISTEN(tier::release, e2::form::prop::filler, clr, -, (term_bgc_ptr)) { term_bgc = clr.bgc(); }; @@ -1028,7 +1028,7 @@ namespace netxs::app::terminal }; }); - inst->attach_property(ui::term::events::colors::bg, terminal::events::release::colors::bg) + term->attach_property(ui::term::events::colors::bg, terminal::events::release::colors::bg) ->attach_property(ui::term::events::colors::fg, terminal::events::release::colors::fg) ->attach_property(ui::term::events::selmod, terminal::events::release::selection::mode) ->attach_property(ui::term::events::onesht, terminal::events::release::selection::shot) diff --git a/src/netxs/desktopio/application.hpp b/src/netxs/desktopio/application.hpp index 38efe65d16..02bea376c8 100644 --- a/src/netxs/desktopio/application.hpp +++ b/src/netxs/desktopio/application.hpp @@ -24,7 +24,7 @@ namespace netxs::app namespace netxs::app::shared { - static const auto version = "v0.9.99.52"; + static const auto version = "v0.9.99.53"; static const auto repository = "https://github.com/directvt/vtm"; static const auto usr_config = "~/.config/vtm/settings.xml"s; static const auto sys_config = "/etc/vtm/settings.xml"s; diff --git a/src/netxs/desktopio/controls.hpp b/src/netxs/desktopio/controls.hpp index 5b6c0096c3..a6338c4b5d 100644 --- a/src/netxs/desktopio/controls.hpp +++ b/src/netxs/desktopio/controls.hpp @@ -1290,7 +1290,7 @@ namespace netxs::ui static constexpr auto focused = 1; // Object can be focused and active, it is focused by default. It cuts the focus tree when focus is set on it. static constexpr auto hub = 2; // Object can't be focused, only active, it is inactive by default. It doesn't cut the focus tree when focus is set on it, it just activate a whole branch. static constexpr auto active = 3; // Object can't be focused, only active, it is active by default. It doesn't cut the focus tree when focus is set on it, it just activate a whole branch. - static constexpr auto relay = 4; // Object is on the process/event domain boundary and can't be focused (gui and ui::dtvt). + static constexpr auto relay = 4; // Object is on the process/event domain boundary and can't be focused (gui and ui::dtvt). Always has default focus. }; template @@ -1363,15 +1363,6 @@ namespace netxs::ui } return gear_id_list; } - static auto pass(sptr src_ptr, sptr dst_ptr) - { - auto lock = src_ptr->bell::sync(); - if (auto parent = src_ptr->parent()) - { - auto gear_id_list = pro::focus::off(src_ptr); - pro::focus::set(dst_ptr, gear_id_list, solo::off); - } - } static auto test(base& item, input::hids& gear) { auto gear_test = item.base::riseup(tier::request, e2::form::state::keybd::find, { gear.id, 0 }); @@ -1379,11 +1370,12 @@ namespace netxs::ui } focus(base&&) = delete; - focus(base& boss, si32 focus_mode = mode::hub, bool cut_scope = faux) + focus(base& boss, si32 focus_mode = mode::hub, bool cut_scope = faux, bool set_default_focus = true) : skill{ boss }, scope{ cut_scope }, node_type{ focus_mode } { + if (set_default_focus) if (node_type == mode::focused || node_type == mode::active || node_type == mode::relay) // Pave default focus path at startup. { boss.LISTEN(tier::anycast, e2::form::upon::started, parent_ptr, memo) @@ -1637,6 +1629,18 @@ namespace netxs::ui route.next.remove_if([&](auto& next){ return next.lock() == seed.item; }); } }; + // pro::focus: Switch all foci to the seed.item. It is used by dtty. + boss.LISTEN(tier::request, hids::events::focus::hop, seed, memo) + { + for (auto& [gear_id, route] : gears) + { + auto is_active = route.active && gear_id; + if (is_active) boss.bell::signal(tier::release, hids::events::focus::off, { .gear_id = gear_id }); + route.next.clear(); + route.next.push_back(seed.item); + if (is_active) boss.bell::signal(tier::release, hids::events::focus::set, { .gear_id = gear_id, .just_activate_only = true }); + } + }; boss.LISTEN(tier::request, e2::form::state::keybd::enlist, gear_id_list, memo) { for (auto& [gear_id, route] : gears) @@ -2102,17 +2106,17 @@ namespace netxs::ui auto action_ptr_list = keybind_ptr->list("action"); bindings.push_back({ .chord = chord, .scheme = scheme }); auto& rec = bindings.back(); - if constexpr (debugmode) log("chord=%% scheme=%%", chord, scheme); + //if constexpr (debugmode) log("chord=%% scheme=%%", chord, scheme); for (auto action_ptr : action_ptr_list) { rec.actions.push_back({ .action = action_ptr->take_value() }); auto& action = rec.actions.back(); - if constexpr (debugmode) log(" action=", action.action); + //if constexpr (debugmode) log(" action=", action.action); auto arg_ptr_list = action_ptr->list("data"); for (auto arg_ptr : arg_ptr_list) { action.args.push_back(arg_ptr->take_value()); - if constexpr (debugmode) log(" data=", action.args.back()); + //if constexpr (debugmode) log(" data=", action.args.back()); } } } diff --git a/src/netxs/desktopio/gui.hpp b/src/netxs/desktopio/gui.hpp index 91c64634ea..faed966aa9 100644 --- a/src/netxs/desktopio/gui.hpp +++ b/src/netxs/desktopio/gui.hpp @@ -2765,9 +2765,8 @@ namespace netxs::gui { if (changed) { - auto timecode = datetime::now(); stream.m.changed++; - stream.m.timecod = timecode; + stream.m.timecod = datetime::now(); stream.m.ctlstat = get_mods_state(); stream.mouse(stream.m); } diff --git a/src/netxs/desktopio/input.hpp b/src/netxs/desktopio/input.hpp index b0891a504a..f2d5df962c 100644 --- a/src/netxs/desktopio/input.hpp +++ b/src/netxs/desktopio/input.hpp @@ -161,6 +161,7 @@ namespace netxs::events::userland EVENT_XS( off, input::foci ), // release: Reset focus toward inside; preview: reset focus toward outside. EVENT_XS( get, input::foci ), // request: Unfocus and delete focus route. EVENT_XS( dry, input::foci ), // request: Remove the reference to the specified applet. + EVENT_XS( hop, input::foci ), // request: Switch focus branch to seed.item. }; SUBSET_XS( device ) { @@ -1176,9 +1177,6 @@ namespace netxs::input si32 virtcod{}; si32 scancod{}; si32 keycode{}; - ui64 vk_hash{}; - ui64 sc_hash{}; - ui64 ch_hash{}; text vkchord{}; text scchord{}; text chchord{}; @@ -1663,7 +1661,16 @@ namespace netxs::input } void set_handled(bool b = true) { - handled = b; + if (keybd::keystat == input::key::released) // Don't stop the key release event, just break the chord processing. + { + keybd::vkchord.clear(); + keybd::scchord.clear(); + keybd::chchord.clear(); + } + else + { + handled = b; + } } void set_hotkey_scheme(qiew scheme) { diff --git a/src/netxs/desktopio/terminal.hpp b/src/netxs/desktopio/terminal.hpp index 61d0492fad..bf5eff5555 100644 --- a/src/netxs/desktopio/terminal.hpp +++ b/src/netxs/desktopio/terminal.hpp @@ -8431,7 +8431,6 @@ namespace netxs::ui gear.m_sys.enabled = hids::stat::halt; stream.sysmouse.send(*this, gear.m_sys); }; - //todo replace it with tier::release hids::events::focus::any (set/off) LISTEN(tier::release, hids::events::focus::any, seed) { auto deed = this->bell::protos(tier::release);