diff --git a/src/netxs/desktopio/application.hpp b/src/netxs/desktopio/application.hpp index 50d527d39f..40c07ee868 100644 --- a/src/netxs/desktopio/application.hpp +++ b/src/netxs/desktopio/application.hpp @@ -21,7 +21,7 @@ namespace netxs::app namespace netxs::app::shared { - static const auto version = "v2026.10.07"; + static const auto version = "v2026.10.08"; 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/gui.hpp b/src/netxs/desktopio/gui.hpp index 3084f4308e..fb9f6f81c7 100644 --- a/src/netxs/desktopio/gui.hpp +++ b/src/netxs/desktopio/gui.hpp @@ -8694,7 +8694,6 @@ namespace netxs::gui auto sr = netxs::start_lifetime_as(read_buffer.data()); session.send_batch([&](auto& batch_buffer) { - auto data_format = (byte)32; // 32-bit. auto destination_id = sr.requester_window_id; if (sr.target_id == session.atom_targets) // Supported clipboard formats requested (TARGETS, UTF8_STRING). { @@ -8755,18 +8754,15 @@ namespace netxs::gui iter->time = sr.time; session.accumrq(batch_buffer, x11::req::change_window_attrs{ .window_id = sr.requester_window_id }, // Track property delete on remote window. x11::req::change_window_attrs::payload{ .event_mask = x11::event::mask::PropertyChange }); - data_format = 0; // Change to AnyFormat. - sr.target_id = session.atom_incr; // Change to INCR. session.accumrq(batch_buffer, x11::req::change_property{ .window_id = sr.requester_window_id, .property = sr.property_id, - .type = sr.target_id }, // "INCR" + .type = session.atom_incr }, // "INCR" netxs::saturate_cast(clipdata.utf8.size())); } } // Notify remote window. session.accumrq(batch_buffer, x11::req::send_event{ .destination_id = destination_id, .event_type = x11::event::SelectionNotify, // SelectionNotify: - .format = data_format, .originator_id = sr.time, // - time .message_type = sr.requester_window_id, // - requester .serial = sr.selection_id, // - selection diff --git a/src/netxs/desktopio/x11.hpp b/src/netxs/desktopio/x11.hpp index b0047a8097..b57273de76 100644 --- a/src/netxs/desktopio/x11.hpp +++ b/src/netxs/desktopio/x11.hpp @@ -9,7 +9,7 @@ namespace netxs::x11 static auto wm_inst_name = "vtm"s; //todo unify (app::vtm::id) static constexpr auto fps = 60; // FPS //todo calc at startup static constexpr auto vbi = std::chrono::microseconds(1s) / x11::fps; // V-blank interval (VBI) - static constexpr auto buffer_read_step = 4096u; // 16 KB in quads. + static constexpr auto buffer_read_step = 16384u - 8u; // ~64 KB in quads. using fd_t = os::fd_t; @@ -2961,6 +2961,41 @@ namespace netxs::x11 } return true; } + auto _sync_get_window_property_type(ui32 window_id, ui32 property_id) + { + auto prop_type = 0u; + sync_buffer.clear(); + auto seq_num = syncrq(sync_buffer, x11::req::get_property{ .remove = 0, + .window_id = window_id, + .property = property_id, + .prop_type = 0, // AnyPropertyType + .long_length = 0 }); + sync_x11connection->send(sync_buffer); + sync_buffer.clear(); + auto ev = x11::event::any{}; + while (sync_x11connection->recv_all((char*)&ev, sizeof(ev)).size() == sizeof(ev)) + { + auto type = ev.type & 0x7f; + if (_filter_errors(ev) && (type == x11::event::Reply || type == x11::event::GenericEvent)) + { + if (ev.length) + { + sync_buffer.assign(ev.length * sizeof(ui32), '\0'); + sync_x11connection->recv_all(sync_buffer.data(), sync_buffer.size()); + } + if (ev.sequence == seq_num) + { + auto prop_reply = netxs::start_lifetime_as(ev); + prop_type = prop_reply.prop_type; + break; + } + } + if (ev.sequence == seq_num) break; + } + sync_buffer.clear(); + if constexpr (debugmode) log(ansi::clr(yellowlt, utf::fprint("prop_type=%% (%%)", _get_atom_name(prop_type), prop_type))); + return prop_type; + } void get_clipboard(input::clipdata& clipdata) { //todo check if we are the clipboard owner @@ -3030,47 +3065,53 @@ namespace netxs::x11 { if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint(" no clipboard data available"))); } - else if(sn.target_id == atom_incr) // Huge data block. INCR requested. + else { - // Read INCR property to preallocate recv buffer and remove it signaling to start INCR. - auto minimal_buffer_size = 0u; - _sync_get_window_property(sync_msg_window_id, sn.property_id, sn.target_id, true, minimal_buffer_size); - if (minimal_buffer_size) - { - clipdata.utf8.reserve(minimal_buffer_size); - } - if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint("clipboard data is large, INCR required, ~recv buffer size=%%", minimal_buffer_size))); - auto ev_loop = x11::event::any{}; - while (sync_x11connection->recv_all((char*)&ev_loop, sizeof(ev_loop)).size() == sizeof(ev_loop)) + auto prop_type = _sync_get_window_property_type(sync_msg_window_id, sn.property_id); + if(prop_type == atom_incr) // Huge data block. INCR requested. { - auto type_loop = ev_loop.type & 0x7f; - if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint(" recv: type=%% (%%)", event_str(type_loop), type_loop))); - if (_sync_filter_unexpected(ev_loop) && type_loop == x11::event::PropertyNotify) + // Read INCR property to preallocate recv buffer and remove it signaling to start INCR. + auto minimal_buffer_size = 0u; + _sync_get_window_property(sync_msg_window_id, sn.property_id, prop_type, true, minimal_buffer_size); + if (minimal_buffer_size) + { + clipdata.utf8.reserve(minimal_buffer_size); + } + if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint("clipboard data is large, INCR required, ~recv buffer size=%%", minimal_buffer_size))); + auto ev_loop = x11::event::any{}; + while (sync_x11connection->recv_all((char*)&ev_loop, sizeof(ev_loop)).size() == sizeof(ev_loop)) { - auto pn = netxs::start_lifetime_as(&ev_loop); - if (pn.window_id == sync_msg_window_id && pn.atom == sn.property_id && pn.state == 0/*new value*/) + auto type_loop = ev_loop.type & 0x7f; + if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint(" recv: type=%% (%%)", event_str(type_loop), type_loop))); + if (_sync_filter_unexpected(ev_loop) && type_loop == x11::event::PropertyNotify) { - auto initial_size = clipdata.utf8.size(); - _sync_get_window_property(sync_msg_window_id, sn.property_id, 0, true, clipdata.utf8); - if (clipdata.utf8.size() == initial_size) // Finalize. + auto pn = netxs::start_lifetime_as(&ev_loop); + if (pn.window_id == sync_msg_window_id && pn.atom == sn.property_id && pn.state == 0/*new value*/) { - break; + auto prev_size = clipdata.utf8.size(); + if constexpr (debugmode) log("chunk prop type=%%", _sync_get_window_property_type(sync_msg_window_id, sn.property_id)); + _sync_get_window_property(sync_msg_window_id, sn.property_id, sn.target_id, true, clipdata.utf8); + if (clipdata.utf8.size() == prev_size) // Finalize. + { + break; + } } } } } - } - else //if (sn.target_id != atom_incr) // Small data block. - { - if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint(" Try to get small clipboard block..."))); - _sync_get_window_property(sync_msg_window_id, sn.property_id/*atom_vtm_clipboard*/, sn.target_id/*atom_utf8_string*/, true, clipdata.utf8); - if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint(" got clipboard: '%%'", utf::debase437(clipdata.utf8)))); + else //if (prop_info.type != atom_incr) // Small data block. + { + if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint(" Try to get small clipboard block..."))); + _sync_get_window_property(sync_msg_window_id, sn.property_id/*atom_vtm_clipboard*/, sn.target_id/*atom_utf8_string*/, true, clipdata.utf8); + if constexpr (debugmode) log(ansi::clr(greenlt, utf::fprint(" got clipboard: '%%...'", utf::debase437(clipdata.utf8).substr(0, std::min(clipdata.utf8.size(), (size_t)40))))); + } } break; } //if (ev.sequence == seq_num) break; } sync_buffer.clear(); + if constexpr (debugmode) log(ansi::clr(yellowlt, "exit from get_clipboard")); } auto enable_detectable_autorepeat() {