mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-19 19:14:53 +00:00
Merge branch 'main' into feat/stardust
This commit is contained in:
commit
e8043de502
7 changed files with 145 additions and 138 deletions
|
@ -22,7 +22,7 @@ cargo:test:
|
|||
script:
|
||||
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
|
||||
- apt-get update
|
||||
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev libjxl-dev -y
|
||||
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev libjxl-dev libvte-2.91-gtk4-dev -y
|
||||
- apt-get install meson ninja-build git desktop-file-utils gettext file libusb-dev libusb-1.0-0-dev curl -y
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/rustup.sh
|
||||
- chmod +x /tmp/rustup.sh
|
||||
|
@ -41,7 +41,7 @@ appimage:
|
|||
script:
|
||||
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
|
||||
- apt-get update
|
||||
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev libjxl-dev -y
|
||||
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev libjxl-dev libvte-2.91-gtk4-dev -y
|
||||
- apt-get install meson ninja-build git desktop-file-utils gettext file libusb-dev libusb-1.0-0-dev curl -y
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/rustup.sh
|
||||
- chmod +x /tmp/rustup.sh
|
||||
|
|
56
Cargo.lock
generated
56
Cargo.lock
generated
|
@ -304,6 +304,7 @@ dependencies = [
|
|||
"sourceview5",
|
||||
"tracker",
|
||||
"uuid",
|
||||
"zoha-vte4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -591,9 +592,9 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
|||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.18.2"
|
||||
version = "0.18.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57052f84e8e5999b258e8adf8f5f2af0ac69033864936b8b6838321db2f759b1"
|
||||
checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -638,9 +639,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.18.2"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c316afb01ce8067c5eaab1fc4f2cd47dc21ce7b6296358605e2ffab23ccbd19"
|
||||
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"futures-channel",
|
||||
|
@ -961,6 +962,17 @@ dependencies = [
|
|||
"hashbrown 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.8.0"
|
||||
|
@ -1375,9 +1387,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.18.0"
|
||||
version = "0.18.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06a9e54b831d033206160096b825f2070cf5fda7e35167b1c01e9e774f9202d1"
|
||||
checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
|
||||
dependencies = [
|
||||
"gio",
|
||||
"glib",
|
||||
|
@ -2417,3 +2429,35 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zoha-vte4"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e09b58dbfab3b62c5544cafadc504db3b7d12f21ac6e55048489dbf90c979caf"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"gdk4",
|
||||
"gio",
|
||||
"glib",
|
||||
"gtk4",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"pango",
|
||||
"zoha-vte4-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zoha-vte4-sys"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "749df284a2c2e68c2c359762b277854d533a4d50c7a216a3adf45cd5e5ee2993"
|
||||
dependencies = [
|
||||
"gdk4-sys",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"gtk4-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"system-deps",
|
||||
]
|
||||
|
|
|
@ -41,3 +41,4 @@ sourceview5 = { version = "0.7.1", features = [
|
|||
] }
|
||||
tracker = "0.2.1"
|
||||
uuid = { version = "1.4.1", features = ["v4", "fast-rng"] }
|
||||
zoha-vte4 = { version = "0.0.2", features = ["v0_72"] }
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::log_level::LogLevel;
|
||||
use crate::log_parser::MonadoLog;
|
||||
use crate::ui::app::{DebugOpenDataAction, DebugOpenPrefixAction};
|
||||
use crate::ui::util::copy_text;
|
||||
use gtk::glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use relm4::prelude::*;
|
||||
use relm4::{ComponentSender, SimpleComponent};
|
||||
use sourceview5::prelude::*;
|
||||
use zoha_vte4::{Terminal, TerminalExt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SearchDirection {
|
||||
|
@ -17,7 +18,8 @@ pub enum SearchDirection {
|
|||
pub enum DebugViewMsg {
|
||||
LogUpdated(Vec<String>),
|
||||
ClearLog,
|
||||
FilterLog(SearchDirection),
|
||||
DoSearch,
|
||||
SearchFindMatch(SearchDirection),
|
||||
LogLevelChanged(LogLevel),
|
||||
XRServiceActiveChanged(bool),
|
||||
SetColorScheme,
|
||||
|
@ -27,30 +29,20 @@ pub enum DebugViewMsg {
|
|||
pub struct DebugView {
|
||||
xrservice_active: bool,
|
||||
#[tracker::do_not_track]
|
||||
textbuf: sourceview5::Buffer,
|
||||
#[tracker::do_not_track]
|
||||
textview: Option<sourceview5::View>,
|
||||
#[tracker::do_not_track]
|
||||
searchbar: Option<gtk::SearchBar>,
|
||||
#[tracker::do_not_track]
|
||||
search_entry: Option<gtk::SearchEntry>,
|
||||
#[tracker::do_not_track]
|
||||
dropdown: Option<gtk::DropDown>,
|
||||
#[tracker::do_not_track]
|
||||
scrolledwin: Option<gtk::ScrolledWindow>,
|
||||
#[tracker::do_not_track]
|
||||
search_ctx: sourceview5::SearchContext,
|
||||
#[tracker::do_not_track]
|
||||
search_settings: sourceview5::SearchSettings,
|
||||
#[tracker::do_not_track]
|
||||
search_mark: Option<gtk::TextMark>,
|
||||
#[tracker::do_not_track]
|
||||
log_level: LogLevel,
|
||||
#[tracker::do_not_track]
|
||||
vte_terminal: Terminal,
|
||||
}
|
||||
|
||||
pub struct DebugViewInit {}
|
||||
|
||||
const MAX_SCROLLBACK: i32 = 2000;
|
||||
const MAX_SCROLLBACK: u32 = 2000;
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for DebugView {
|
||||
|
@ -68,11 +60,10 @@ impl SimpleComponent for DebugView {
|
|||
}
|
||||
|
||||
view! {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
adw::ToolbarView {
|
||||
set_hexpand: true,
|
||||
set_vexpand: true,
|
||||
adw::HeaderBar {
|
||||
add_top_bar: hb = &adw::HeaderBar {
|
||||
set_hexpand: true,
|
||||
set_vexpand: false,
|
||||
add_css_class: "flat",
|
||||
|
@ -87,8 +78,7 @@ impl SimpleComponent for DebugView {
|
|||
},
|
||||
pack_start: &log_level_dropdown,
|
||||
},
|
||||
#[name(searchbar)]
|
||||
gtk::SearchBar {
|
||||
add_top_bar: searchbar = >k::SearchBar {
|
||||
set_margin_start: 1,
|
||||
set_hexpand: true,
|
||||
#[chain(flags(gtk::glib::BindingFlags::BIDIRECTIONAL).build())]
|
||||
|
@ -102,44 +92,34 @@ impl SimpleComponent for DebugView {
|
|||
gtk::SearchEntry {
|
||||
set_hexpand: true,
|
||||
connect_changed[sender] => move |_| {
|
||||
sender.input(Self::Input::FilterLog(SearchDirection::Forward));
|
||||
sender.input(Self::Input::DoSearch);
|
||||
},
|
||||
connect_activate[sender] => move |_| {
|
||||
sender.input(Self::Input::FilterLog(SearchDirection::Forward));
|
||||
sender.input(Self::Input::SearchFindMatch(SearchDirection::Forward));
|
||||
},
|
||||
},
|
||||
gtk::Button {
|
||||
set_icon_name: "go-up-symbolic",
|
||||
set_tooltip_text: Some("Previous Match"),
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(Self::Input::FilterLog(SearchDirection::Backward))
|
||||
sender.input(Self::Input::SearchFindMatch(SearchDirection::Backward))
|
||||
},
|
||||
},
|
||||
gtk::Button {
|
||||
set_icon_name: "go-down-symbolic",
|
||||
set_tooltip_text: Some("Next Match"),
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(Self::Input::FilterLog(SearchDirection::Forward))
|
||||
sender.input(Self::Input::SearchFindMatch(SearchDirection::Forward))
|
||||
},
|
||||
},
|
||||
},
|
||||
connect_entry: &search_entry,
|
||||
},
|
||||
#[name(scrolledwin)]
|
||||
gtk::ScrolledWindow {
|
||||
#[wrap(Some)]
|
||||
set_content: sw = >k::ScrolledWindow {
|
||||
set_hexpand: true,
|
||||
set_vexpand: true,
|
||||
add_css_class: "undershoot-top",
|
||||
#[name(textview)]
|
||||
sourceview5::View {
|
||||
add_css_class: "sourceview-transparent-bg",
|
||||
set_margin_start: 1,
|
||||
set_hexpand: true,
|
||||
set_vexpand: true,
|
||||
set_editable: false,
|
||||
set_monospace: true,
|
||||
set_buffer: Some(&model.textbuf),
|
||||
},
|
||||
model.vte_terminal.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,85 +137,51 @@ impl SimpleComponent for DebugView {
|
|||
Self::Input::LogLevelChanged(lvl) => {
|
||||
self.log_level = lvl;
|
||||
}
|
||||
Self::Input::FilterLog(direction) => {
|
||||
Self::Input::DoSearch => {
|
||||
let searchbar = self.searchbar.as_ref().unwrap().clone();
|
||||
let search_entry = self.search_entry.as_ref().unwrap().clone();
|
||||
let search_text = search_entry.text().to_string();
|
||||
if searchbar.is_search_mode() && !search_text.is_empty() {
|
||||
self.search_settings
|
||||
.set_search_text(Some(search_text.as_str()));
|
||||
self.search_mark = Some(self.textbuf.get_insert());
|
||||
let mut iter = self
|
||||
.textbuf
|
||||
.iter_at_mark(self.search_mark.as_ref().unwrap());
|
||||
iter.forward_char();
|
||||
let search_res = match direction {
|
||||
SearchDirection::Forward => self.search_ctx.forward(&iter),
|
||||
SearchDirection::Backward => self.search_ctx.backward(&iter),
|
||||
};
|
||||
match search_res {
|
||||
None => {
|
||||
// TODO: mark search entry red
|
||||
}
|
||||
Some((start, end, _)) => {
|
||||
self.textbuf.move_mark(
|
||||
self.search_mark.as_ref().unwrap(),
|
||||
match direction {
|
||||
SearchDirection::Forward => &end,
|
||||
SearchDirection::Backward => &start,
|
||||
},
|
||||
);
|
||||
self.textbuf.select_range(&start, &end);
|
||||
self.textview
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.scroll_mark_onscreen(&self.textbuf.create_mark(None, &end, false));
|
||||
}
|
||||
if let Ok(regex) = zoha_vte4::Regex::for_search(&search_text, 0) {
|
||||
self.vte_terminal.search_set_regex(Some(®ex), 0);
|
||||
}
|
||||
} else {
|
||||
self.search_settings.set_search_text(None);
|
||||
self.vte_terminal.search_set_regex(None, 0);
|
||||
}
|
||||
}
|
||||
Self::Input::SearchFindMatch(direction) => match direction {
|
||||
SearchDirection::Forward => {
|
||||
self.vte_terminal.search_find_next();
|
||||
}
|
||||
SearchDirection::Backward => {
|
||||
self.vte_terminal.search_find_previous();
|
||||
}
|
||||
},
|
||||
Self::Input::LogUpdated(n_log) => {
|
||||
for row in n_log {
|
||||
let txt = match MonadoLog::new_from_str(row.as_str()) {
|
||||
Some(o) => match o.level >= self.log_level {
|
||||
false => None,
|
||||
true => Some(format!(
|
||||
"{lvl}\t[{file}:{func}]\n\t{msg}\n",
|
||||
"{lvl}\t[{file}:{func}]\r\n\t{msg}\r\n",
|
||||
lvl = o.level,
|
||||
file = o.file,
|
||||
func = o.func,
|
||||
msg = o.message
|
||||
msg = o.message.replace("\n", "\r\n")
|
||||
)),
|
||||
},
|
||||
None => Some(row),
|
||||
};
|
||||
if let Some(t) = txt {
|
||||
self.textbuf
|
||||
.insert(&mut self.textbuf.end_iter(), t.as_str());
|
||||
self.vte_terminal.feed(t.as_bytes())
|
||||
}
|
||||
}
|
||||
if !self.searchbar.as_ref().unwrap().is_search_mode() {
|
||||
let textbuf = self.textbuf.clone();
|
||||
let textview = self.textview.as_ref().unwrap().clone();
|
||||
gtk::glib::idle_add_local_once(move || {
|
||||
let end_mark = textbuf.create_mark(None, &textbuf.end_iter(), false);
|
||||
textview.scroll_mark_onscreen(&end_mark);
|
||||
});
|
||||
}
|
||||
while self.textbuf.line_count() > MAX_SCROLLBACK {
|
||||
let mut start = self.textbuf.start_iter();
|
||||
let mut end = self.textbuf.start_iter();
|
||||
end.forward_line();
|
||||
self.textbuf.delete(&mut start, &mut end);
|
||||
}
|
||||
}
|
||||
Self::Input::ClearLog => {
|
||||
self.textbuf.set_text("");
|
||||
self.vte_terminal.feed("\x1bc".as_bytes());
|
||||
}
|
||||
Self::Input::SetColorScheme => {
|
||||
Self::set_color_scheme(&self.textbuf);
|
||||
Self::set_color_scheme(&self.vte_terminal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,19 +191,6 @@ impl SimpleComponent for DebugView {
|
|||
root: &Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let textbuf = sourceview5::Buffer::builder()
|
||||
.highlight_syntax(false)
|
||||
.enable_undo(false)
|
||||
.build();
|
||||
let search_settings = sourceview5::SearchSettings::builder()
|
||||
.wrap_around(true)
|
||||
.case_sensitive(false)
|
||||
.build();
|
||||
let search_ctx = sourceview5::SearchContext::builder()
|
||||
.buffer(&textbuf)
|
||||
.settings(&search_settings)
|
||||
.build();
|
||||
|
||||
let log_level_dropdown = gtk::DropDown::from_strings(
|
||||
LogLevel::iter()
|
||||
.map(|lvl| lvl.to_string())
|
||||
|
@ -282,46 +215,67 @@ impl SimpleComponent for DebugView {
|
|||
adw::StyleManager::default().connect_dark_notify(clone!(@strong sender => move |_| {
|
||||
sender.input(Self::Input::SetColorScheme);
|
||||
}));
|
||||
Self::set_color_scheme(&textbuf);
|
||||
|
||||
let mut model = Self {
|
||||
xrservice_active: false,
|
||||
tracker: 0,
|
||||
textbuf,
|
||||
textview: None,
|
||||
searchbar: None,
|
||||
search_entry: None,
|
||||
dropdown: None,
|
||||
scrolledwin: None,
|
||||
search_settings,
|
||||
search_ctx,
|
||||
search_mark: None,
|
||||
log_level: LogLevel::Trace,
|
||||
vte_terminal: {
|
||||
let t = Terminal::builder()
|
||||
.scroll_on_output(true)
|
||||
.scrollback_lines(MAX_SCROLLBACK)
|
||||
.scroll_unit_is_pixels(true)
|
||||
.vexpand(true)
|
||||
.hexpand(true)
|
||||
.build();
|
||||
t.set_clear_background(false);
|
||||
t.search_set_wrap_around(true);
|
||||
Self::set_color_scheme(&t);
|
||||
t
|
||||
},
|
||||
};
|
||||
|
||||
{
|
||||
let sc = gtk::ShortcutController::new();
|
||||
let term = model.vte_terminal.clone();
|
||||
sc.add_shortcut(gtk::Shortcut::new(
|
||||
gtk::ShortcutTrigger::parse_string("<Control>c"),
|
||||
Some(gtk::CallbackAction::new(move |_, _| {
|
||||
if let Some(text) = term.text_selected(zoha_vte4::Format::Text) {
|
||||
copy_text(text.as_str());
|
||||
}
|
||||
true
|
||||
})),
|
||||
));
|
||||
let term = model.vte_terminal.clone();
|
||||
sc.add_shortcut(gtk::Shortcut::new(
|
||||
gtk::ShortcutTrigger::parse_string("<Control>a"),
|
||||
Some(gtk::CallbackAction::new(move |_, _| {
|
||||
term.select_all();
|
||||
true
|
||||
})),
|
||||
));
|
||||
model.vte_terminal.add_controller(sc);
|
||||
}
|
||||
|
||||
let widgets = view_output!();
|
||||
model.searchbar = Some(widgets.searchbar.clone());
|
||||
model.search_entry = Some(widgets.search_entry.clone());
|
||||
model.textview = Some(widgets.textview.clone());
|
||||
model.dropdown = Some(log_level_dropdown.clone());
|
||||
model.scrolledwin = Some(widgets.scrolledwin.clone());
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugView {
|
||||
fn set_color_scheme(textbuf: &sourceview5::Buffer) {
|
||||
let sourceview_scheme_name = if adw::StyleManager::default().is_dark() {
|
||||
"Adwaita-dark"
|
||||
fn set_color_scheme(term: &Terminal) {
|
||||
if adw::StyleManager::default().is_dark() {
|
||||
term.set_color_foreground(>k::gdk::RGBA::new(1.0, 1.0, 1.0, 1.0));
|
||||
} else {
|
||||
"Adwaita"
|
||||
};
|
||||
if let Some(scheme) = &sourceview5::StyleSchemeManager::new().scheme(sourceview_scheme_name)
|
||||
{
|
||||
textbuf.set_style_scheme(Some(scheme));
|
||||
} else {
|
||||
println!("gtksourceview style scheme not found")
|
||||
term.set_color_foreground(>k::gdk::RGBA::new(0.0, 0.0, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::ui::app::{
|
|||
use crate::ui::profile_editor::ProfileEditorInit;
|
||||
use crate::ui::stardust::stardust_view::StardustViewInit;
|
||||
use crate::ui::steamvr_calibration_box::SteamVrCalibrationBoxMsg;
|
||||
use crate::ui::util::{limit_dropdown_width, warning_heading};
|
||||
use crate::ui::util::{copy_text, limit_dropdown_width, warning_heading};
|
||||
use crate::xr_devices::XRDevice;
|
||||
use gtk::prelude::*;
|
||||
use relm4::adw::traits::MessageDialogExt;
|
||||
|
@ -325,10 +325,9 @@ impl SimpleComponent for MainView {
|
|||
set_valign: gtk::Align::Center,
|
||||
connect_clicked => move |_| {
|
||||
if let Some(GpuSysDrm::Amd(d)) = get_first_amd_gpu() {
|
||||
gtk::gdk::Display::default()
|
||||
.expect("Could not find default display")
|
||||
.clipboard()
|
||||
.set_text(get_set_amd_vr_pow_prof_cmd(d.as_str()).as_str());
|
||||
copy_text(
|
||||
&get_set_amd_vr_pow_prof_cmd(d.as_str())
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use super::util::copy_text;
|
||||
use crate::{constants::APP_NAME, profile::Profile};
|
||||
use gtk::prelude::*;
|
||||
use relm4::prelude::*;
|
||||
|
@ -100,10 +101,7 @@ impl SimpleComponent for SteamLaunchOptionsBox {
|
|||
self.set_launch_options(prof.get_steam_launch_options());
|
||||
}
|
||||
Self::Input::CopyLaunchOptions => {
|
||||
gtk::gdk::Display::default()
|
||||
.expect("Could not find default display")
|
||||
.clipboard()
|
||||
.set_text(self.launch_options.as_str());
|
||||
copy_text(self.launch_options.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gtk4::{gio, prelude::*};
|
||||
use gtk4::{gdk, gio, prelude::*};
|
||||
|
||||
pub fn limit_dropdown_width(dd: >k4::DropDown, chars: i32) {
|
||||
let mut dd_child = dd
|
||||
|
@ -50,3 +50,14 @@ pub fn open_with_default_handler(uri: &str) {
|
|||
eprintln!("Error opening uri {}: {}", uri, e)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn copy_text(txt: &str) {
|
||||
match gdk::Display::default() {
|
||||
None => {
|
||||
eprintln!("Warning: could not get default gdk display")
|
||||
}
|
||||
Some(d) => {
|
||||
d.clipboard().set_text(txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue