Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X11 clipboard support #5479

Closed
wants to merge 10 commits into from
@@ -52,6 +52,9 @@ git = "https://github.com/servo/rust-core-text"
[dependencies.gleam]
git = "https://github.com/servo/gleam"

[dependencies.clipboard]
git = "https://github.com/aweinstock314/rust-x11-clipboard"

[dependencies]
url = "0.2.16"
time = "0.1.17"
@@ -38,6 +38,7 @@ use util::cursor::Cursor;
use util::geometry::PagePx;
use util::opts;
use util::task::spawn_named;
use clipboard::ClipboardContext;

/// Maintains the pipelines and navigation context and grants permission to composite.
pub struct Constellation<LTF, STF> {
@@ -99,6 +100,9 @@ pub struct Constellation<LTF, STF> {
phantom: PhantomData<(LTF, STF)>,

pub window_size: WindowSizeData,

/// Means of accessing the clipboard
clipboard_ctx: ClipboardContext,
}

/// Stores the navigation context for a single frame in the frame tree.
@@ -208,6 +212,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
device_pixel_ratio: ScaleFactor::new(1.0),
},
phantom: PhantomData,
clipboard_ctx: ClipboardContext::new().unwrap(),
};
constellation.run();
});
@@ -383,6 +388,16 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
subpage_id,
event);
}
ConstellationMsg::GetClipboardContents(sender) => {
let result = match self.clipboard_ctx.get_contents() {
Ok(s) => s,
Err(e) => {
debug!("Error getting clipboard contents ({}), defaulting to empty string", e);
"".to_string()
},
};
sender.send(result).unwrap();
}
}
true
}
@@ -27,6 +27,7 @@ extern crate profile;
#[macro_use]
extern crate util;
extern crate gleam;
extern crate clipboard;

extern crate libc;
extern crate time;
@@ -218,6 +218,8 @@ pub enum Msg {
ChangeRunningAnimationsState(PipelineId, bool),
/// Requests that the constellation instruct layout to begin a new tick of the animation.
TickAnimation(PipelineId),
/// Requests that the constellation retrieve the current contents of the clipboard
GetClipboardContents(Sender<String>),
}

// https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events
@@ -29,6 +29,7 @@ use dom::htmlformelement::{SubmittedFrom, ResetFrom};
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeDamage, NodeTypeId};
use dom::node::{document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::WindowHelpers;
use textinput::TextInput;
use textinput::KeyReaction::{TriggerDefaultAction, DispatchInput, Nothing};
use textinput::Lines::Single;
@@ -108,6 +109,7 @@ static DEFAULT_INPUT_SIZE: u32 = 20;

impl HTMLInputElement {
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLInputElement {
let chan = document.window().root().r().constellation_chan();
HTMLInputElement {
htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLInputElement, localName, prefix, document),
input_type: Cell::new(InputType::InputText),
@@ -116,7 +118,7 @@ impl HTMLInputElement {
checked_changed: Cell::new(false),
value_changed: Cell::new(false),
size: Cell::new(DEFAULT_INPUT_SIZE),
textinput: DOMRefCell::new(TextInput::new(Single, "".to_owned())),
textinput: DOMRefCell::new(TextInput::new(Single, "".to_owned(), chan)),
activation_state: DOMRefCell::new(InputActivationState::new())
}
}
@@ -27,6 +27,7 @@ use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeDamage, NodeTypeId}
use dom::node::{document_from_node, window_from_node};
use textinput::{TextInput, Lines, KeyReaction};
use dom::virtualmethods::VirtualMethods;
use dom::window::WindowHelpers;
use script_task::{ScriptMsg, Runnable};

use util::str::DOMString;
@@ -90,9 +91,10 @@ static DEFAULT_ROWS: u32 = 2;

impl HTMLTextAreaElement {
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTextAreaElement {
let chan = document.window().root().r().constellation_chan();
HTMLTextAreaElement {
htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLTextAreaElement, localName, prefix, document),
textinput: DOMRefCell::new(TextInput::new(Lines::Multiple, "".to_owned())),
textinput: DOMRefCell::new(TextInput::new(Lines::Multiple, "".to_owned(), chan)),
cols: Cell::new(DEFAULT_COLS),
rows: Cell::new(DEFAULT_ROWS),
value_changed: Cell::new(false),
@@ -6,13 +6,16 @@

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::Msg as ConstellationMsg;
use dom::keyboardevent::KeyboardEvent;
use util::str::DOMString;

use std::borrow::ToOwned;
use std::cmp::{min, max};
use std::default::Default;
use std::num::SignedInt;
use std::sync::mpsc::channel;

#[derive(Copy, PartialEq)]
enum Selection {
@@ -40,6 +43,7 @@ pub struct TextInput {
selection_begin: Option<TextPoint>,
/// Is this a multiline input?
multiline: bool,
constellation_channel: ConstellationChan
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
@@ -87,12 +91,13 @@ fn is_control_key(event: JSRef<KeyboardEvent>) -> bool {

impl TextInput {
/// Instantiate a new text input control
pub fn new(lines: Lines, initial: DOMString) -> TextInput {
pub fn new(lines: Lines, initial: DOMString, cc: ConstellationChan) -> TextInput {
let mut i = TextInput {
lines: vec!(),
edit_point: Default::default(),
selection_begin: None,
multiline: lines == Lines::Multiple,
constellation_channel: cc,
};
i.set_content(initial);
i
@@ -118,6 +123,15 @@ impl TextInput {
self.replace_selection(ch.to_string());
}

/// Insert a string at the current editing point
fn insert_string(&mut self, s: &str) {
// it looks like this could be made performant by avoiding some redundant
// selection-related checks, but use the simple implementation for now
for ch in s.chars() {
self.insert_char(ch);
}
}

fn get_sorted_selection(&self) -> (TextPoint, TextPoint) {
let begin = self.selection_begin.unwrap();
let end = self.edit_point;
@@ -282,10 +296,17 @@ impl TextInput {
self.select_all();
KeyReaction::Nothing
},
"v" if is_control_key(event) => {
let (tx, rx) = channel();
self.constellation_channel.0.send(ConstellationMsg::GetClipboardContents(tx)).unwrap();
let contents = rx.recv().unwrap();
self.insert_string(contents.as_slice());
KeyReaction::DispatchInput
},
// printable characters have single-character key values
c if c.len() == 1 => {
self.insert_char(c.char_at(0));
return KeyReaction::DispatchInput;
KeyReaction::DispatchInput
}
"Space" => {
self.insert_char(' ');

Some generated files are not rendered by default. Learn more.

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.