Skip to content

Commit

Permalink
#273 WIP: Bidirectional clipboard sync (win32, our format forwarding)
Browse files Browse the repository at this point in the history
  • Loading branch information
o-sdn-o committed Dec 7, 2022
1 parent f956f49 commit 2294524
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 79 deletions.
2 changes: 1 addition & 1 deletion src/netxs/apps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ namespace netxs::app::shared

if (old_title.size()) // Copy old title to clipboard.
{
gear.set_clip_data(dot_00, clip{ old_title, clip::ansitext });
gear.set_clip_data(clip{ dot_00, old_title, clip::ansitext });
}
};
};
Expand Down
56 changes: 53 additions & 3 deletions src/netxs/console/ansi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,63 @@ namespace netxs::ansi
count,
};

text utf8{};
mime kind{ mime::ansitext };
twod size;
text utf8;
mime kind;

clip()
: kind{ mime::ansitext }
{ }
clip(twod const& size, view utf8, mime kind)
: size{ size },
utf8{ utf8 },
kind{ kind }
{ }
void set(clip const& data)
{
size = dot_00;
auto rawdata = view{ data.utf8 };
if (data.kind == mime::disabled)
{
kind = ansi::clip::textonly;
// rawdata=mime/size_x/size_y;data
if (rawdata.starts_with(ansi::mimeansi)) { rawdata.remove_prefix(ansi::mimeansi.length()); kind = mime::ansitext; }
else if (rawdata.starts_with(ansi::mimetext)) { rawdata.remove_prefix(ansi::mimetext.length()); kind = mime::textonly; }
else if (rawdata.starts_with(ansi::mimerich)) { rawdata.remove_prefix(ansi::mimerich.length()); kind = mime::richtext; }
else if (rawdata.starts_with(ansi::mimehtml)) { rawdata.remove_prefix(ansi::mimehtml.length()); kind = mime::htmltext; }
else if (rawdata.starts_with(ansi::mimesafe)) { rawdata.remove_prefix(ansi::mimesafe.length()); kind = mime::safetext; }
else
{
rawdata = {};
}
if (rawdata.size())
{
rawdata.remove_prefix(1);
if (auto v = utf::to_int(rawdata))
{
size.x = std::abs(v.value());
rawdata.remove_prefix(1);
if (auto v = utf::to_int(rawdata))
{
size.y = std::abs(v.value());
if (rawdata.size()) rawdata.remove_prefix(1);
}
else size.x = 0;
}
}
}
else kind = data.kind;
utf8 = rawdata;
size = rawdata.empty() ? dot_00
: size ? size
: data.size ? data.size
: twod{ 80,25 }; //todo make it configurable
}
void clear()
{
utf8.clear();
kind = mime::ansitext;
size = dot_00;
}
};

Expand Down Expand Up @@ -638,7 +688,7 @@ namespace netxs::ansi
auto& save_palette() { return add("\033[#P" ); } // esc: Push palette onto stack XTPUSHCOLORS.
auto& load_palette() { return add("\033[#Q" ); } // esc: Pop palette from stack XTPOPCOLORS.
auto& old_palette_reset() { return add("\033]R" ); } // esc: Reset color palette (Linux console).
auto& clipbuf(twod size, clip::mime kind, view utf8) // esc: Set clipboard buffer.
auto& clipbuf(twod size, view utf8, clip::mime kind) // esc: Set clipboard buffer.
{
return add("\033]52;", kind == clip::htmltext ? mimehtml
: kind == clip::richtext ? mimerich
Expand Down
86 changes: 21 additions & 65 deletions src/netxs/console/console.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ namespace netxs::events::userland
EVENT_XS( preclose, const bool ), // release: signal to quit after idle timeout, arg: bool - ready to shutdown.
EVENT_XS( quit , const text ), // release: quit, arg: text - bye msg.
EVENT_XS( pointer , const bool ), // release: mouse pointer visibility.
EVENT_XS( clipdata, const ansi::clip), // release: OS clipboard update.
EVENT_XS( clipdata, ansi::clip ), // release: OS clipboard update.
//EVENT_XS( menu , si32 ),
};
SUBSET_XS( data )
Expand Down Expand Up @@ -3583,7 +3583,6 @@ namespace netxs::console
conf& props;
clip clip_rawdata{}; // topgear: Clipboard data.
face clip_preview{}; // topgear: Clipboard preview render.
twod preview_size{}; // topgear: Clipboard preview render size.
bool not_directvt{}; // topgear: Is it the top level gear (not directvt).

template<class ...Args>
Expand All @@ -3596,65 +3595,26 @@ namespace netxs::console
bool clear_clip_data() override
{
auto not_empty = !!clip_rawdata.utf8.size();
preview_size = dot_00;
clip_rawdata.clear();
owner.SIGNAL(tier::release, hids::events::clipbrd::set, *this);
if (not_directvt)
{
clip_preview.size(preview_size);
clip_preview.size(clip_rawdata.size);
}
return not_empty;
}
void set_clip_data(twod const& size, clip const& data, bool forward = true) override
{
auto rawsize = dot_00;
auto rawdata = view{ data.utf8 };
if (data.kind == clip::disabled)
{
clip_rawdata.kind = ansi::clip::textonly;
// rawdata=mime/size_x/size_y;data
if (rawdata.starts_with(ansi::mimeansi)) { rawdata.remove_prefix(ansi::mimeansi.length()); clip_rawdata.kind = ansi::clip::ansitext; }
else if (rawdata.starts_with(ansi::mimetext)) { rawdata.remove_prefix(ansi::mimetext.length()); clip_rawdata.kind = ansi::clip::textonly; }
else if (rawdata.starts_with(ansi::mimerich)) { rawdata.remove_prefix(ansi::mimerich.length()); clip_rawdata.kind = ansi::clip::richtext; }
else if (rawdata.starts_with(ansi::mimehtml)) { rawdata.remove_prefix(ansi::mimehtml.length()); clip_rawdata.kind = ansi::clip::htmltext; }
else if (rawdata.starts_with(ansi::mimesafe)) { rawdata.remove_prefix(ansi::mimesafe.length()); clip_rawdata.kind = ansi::clip::safetext; }
else
{
rawdata = {};
}
if (rawdata.size())
{
rawdata.remove_prefix(1);
if (auto v = utf::to_int(rawdata))
{
rawsize.x = std::abs(v.value());
rawdata.remove_prefix(1);
if (auto v = utf::to_int(rawdata))
{
rawsize.y = std::abs(v.value());
if (rawdata.size()) rawdata.remove_prefix(1);
}
else rawsize.x = 0;
}
}
}
else clip_rawdata.kind = data.kind;

preview_size = rawdata.empty() ? dot_00
: rawsize ? rawsize
: size ? size
: preview_size ? preview_size
: twod{ 80,25 }; //todo make it configurable
clip_rawdata.utf8 = rawdata;
void set_clip_data(clip const& data, bool forward = true) override
{
clip_rawdata.set(data);
if (not_directvt)
{
auto clip_shadow_size = props.clip_preview_glow;
auto draw_shadow = [&](auto& block)
{
clip_preview.mark(cell{});
clip_preview.wipe();
clip_preview.size(dot_21 * clip_shadow_size * 2 + preview_size);
auto full = rect{ dot_21 * clip_shadow_size + dot_21, preview_size };
clip_preview.size(dot_21 * clip_shadow_size * 2 + clip_rawdata.size);
auto full = rect{ dot_21 * clip_shadow_size + dot_21, clip_rawdata.size };
while (clip_shadow_size--)
{
clip_preview.reset();
Expand All @@ -3668,25 +3628,24 @@ namespace netxs::console
};
if (clip_rawdata.kind == clip::safetext)
{
auto blank = " Protected Data "sv;
auto blank = ansi::bgc(0x7Fffffff).fgc(0xFF000000).add(" Protected Data "); //todo unify (i18n)
auto block = page{ blank };
preview_size = twod{ static_cast<si32>(blank.size()), 1 }; //todo unify (i18n)
clip_rawdata.size = block.current().size();
if (clip_shadow_size) draw_shadow(block);
else
{
clip_preview.size(preview_size);
clip_preview.size(clip_rawdata.size);
clip_preview.wipe();
}
clip_preview.mark(cell{}.bgc(0x7Fffffff).fgc(0xFF000000));
clip_preview.output(block);
}
else
{
auto block = page{ rawdata };
auto block = page{ clip_rawdata.utf8 };
if (clip_shadow_size) draw_shadow(block);
else
{
clip_preview.size(preview_size);
clip_preview.size(clip_rawdata.size);
clip_preview.wipe();
}
clip_preview.mark(cell{});
Expand Down Expand Up @@ -3748,7 +3707,7 @@ namespace netxs::console
data.s11n(xmap, gear.slot);
if (data.length())
{
gear.set_clip_data(gear.slot.size, clip{ data, clip::ansitext });
gear.set_clip_data(clip{ gear.slot.size, data, clip::ansitext });
}
};
boss.SUBMIT_T(tier::release, e2::form::prop::brush, memo, brush)
Expand Down Expand Up @@ -3820,7 +3779,7 @@ namespace netxs::console
}
return std::pair{ id_t{}, sptr<topgear>{} };
}
auto set_clip_data(twod const& size, clip const& clipdata)
auto set_clip_data(clip const& clipdata)
{
if (gears.empty())
{
Expand All @@ -3829,7 +3788,7 @@ namespace netxs::console
for (auto& [id, gear_ptr] : gears)
{
auto& gear = *gear_ptr;
gear.set_clip_data(size, clipdata, faux);
gear.set_clip_data(clipdata, faux);
}
}
};
Expand Down Expand Up @@ -5222,7 +5181,7 @@ namespace netxs::console
void handle(s11n::xs::osclipdata lock)
{
auto& item = lock.thing;
notify(e2::conio::clipdata, clip{ item.data, static_cast<clip::mime>(item.mimetype) });
notify(e2::conio::clipdata, clip{ dot_00, item.data, static_cast<clip::mime>(item.mimetype) });
}
void handle(s11n::xs::syskeybd lock)
{
Expand Down Expand Up @@ -5606,13 +5565,10 @@ namespace netxs::console
SIGNAL(tier::preview, e2::form::prop::ui::header, conf_usr_name);
base::moveby(props.coor);

//todo hids
//clip_preview.size(props.clip_preview_size); //todo unify/make it configurable

auto& canal = *termio;
link conio{ canal, This() }; // gate: Terminal IO.
diff paint{ canal, vtmode }; // gate: Rendering loop.
subs token; // gate: Subscription tokens.
subs token; // gate: Subscription tokens.

auto rebuild_scene = [&](bool damaged)
{
Expand Down Expand Up @@ -5726,7 +5682,8 @@ namespace netxs::console
{
if (!direct)
{
input.set_clip_data(base::size() / 2, clipdata);
clipdata.size = base::size() / 2;
input.set_clip_data(clipdata);
base::deface();
}
};
Expand Down Expand Up @@ -5812,9 +5769,8 @@ namespace netxs::console
auto [ext_gear_id, gear_ptr] = input.get_foreign_gear_id(myid);
auto& gear =*gear_ptr;
auto& data = gear.clip_rawdata;
auto& size = gear.preview_size;
if (direct) conio.set_clipboard.send(canal, ext_gear_id, size, data.utf8, data.kind);
else conio.output(ansi::clipbuf(size, data.kind, data.utf8)); // OSC 52
if (direct) conio.set_clipboard.send(canal, ext_gear_id, data.size, data.utf8, data.kind);
else conio.output(ansi::clipbuf( data.size, data.utf8, data.kind));
};
SUBMIT_T(tier::release, hids::events::clipbrd::get, token, from_gear)
{
Expand Down
2 changes: 1 addition & 1 deletion src/netxs/console/input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ namespace netxs::input
si32 countdown = 0;

virtual bool clear_clip_data() = 0;
virtual void set_clip_data(twod const& size, clip const& data, bool forward = true) = 0;
virtual void set_clip_data(clip const& data, bool forward = true) = 0;
virtual clip get_clip_data() = 0;

auto tooltip_enabled()
Expand Down
9 changes: 4 additions & 5 deletions src/netxs/console/terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6052,9 +6052,8 @@ namespace netxs::ui
if (auto ptr = bell::getref(gate_id))
if (auto gear_ptr = std::dynamic_pointer_cast<hids>(ptr))
{
//todo take MIME type from the OSC52 first arg
if constexpr (Decode) gear_ptr->set_clip_data(target->panel, clip{ utf::unbase64(utf::remain(data, ';')), clip::ansitext });
else gear_ptr->set_clip_data(target->panel, clip{ text{ data }, clip::ansitext });
if constexpr (Decode) gear_ptr->set_clip_data(clip{ target->panel, utf::unbase64(data), clip::disabled });
else gear_ptr->set_clip_data(clip{ target->panel, data, clip::ansitext });
}
}
}
Expand Down Expand Up @@ -6480,7 +6479,7 @@ namespace netxs::ui
auto state = gear.state();
gear.combine_focus = true; // Preserve all selected panes.
gear.offer_kb_focus(this->This());
gear.set_clip_data(target->panel, clip{ data, mimetype });
gear.set_clip_data(clip{ target->panel, data, mimetype });
gear.state(state);
}
if (gear.meta(hids::anyCtrl) || selection_cancel(gear)) // Keep selection if Ctrl is pressed.
Expand Down Expand Up @@ -7119,7 +7118,7 @@ namespace netxs::ui
if (auto ptr = bell::getref(c.gear_id))
if (auto gear_ptr = std::dynamic_pointer_cast<hids>(ptr))
{
gear_ptr->set_clip_data(c.clip_prev_size, clip{ c.clipdata, static_cast<clip::mime>(c.mimetype) });
gear_ptr->set_clip_data(clip{ c.clip_prev_size, c.clipdata, static_cast<clip::mime>(c.mimetype) });
}
}
void handle(s11n::xs::request_clipboard lock)
Expand Down
8 changes: 4 additions & 4 deletions src/netxs/os/system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1904,21 +1904,21 @@ namespace netxs::os
{
auto post = page{ utf8 };
auto rich = post.to_rich();
yield.clipbuf(size, clip::richtext, rich);
yield.clipbuf(size, rich, clip::richtext);
}
else if (mime.starts_with(ansi::mimehtml))
{
auto post = page{ utf8 };
auto [html, code] = post.to_html();
yield.clipbuf(size, clip::htmltext, code);
yield.clipbuf(size, code, clip::htmltext);
}
else if (mime.starts_with(ansi::mimeansi)) //todo GH#216
{
yield.clipbuf(size, clip::ansitext, utf8);
yield.clipbuf(size, utf8, clip::ansitext);
}
else
{
yield.clipbuf(size, clip::textonly, utf8);
yield.clipbuf(size, utf8, clip::textonly);
}
os::send<true>(STDOUT_FD, yield.data(), yield.size());
success = true;
Expand Down

0 comments on commit 2294524

Please sign in to comment.