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 #5547

Merged
merged 6 commits into from Apr 21, 2015
@@ -28,7 +28,7 @@ On Debian-based Linuxes:
sudo apt-get install curl freeglut3-dev \
libfreetype6-dev libgl1-mesa-dri libglib2.0-dev xorg-dev \
msttcorefonts gperf g++ cmake python-virtualenv \
libssl-dev libbz2-dev libosmesa6-dev
libssl-dev libbz2-dev libosmesa6-dev libxmu6 libxmu-dev
```

On Fedora:
@@ -37,7 +37,7 @@ On Fedora:
sudo yum install curl freeglut-devel libtool gcc-c++ libXi-devel \
freetype-devel mesa-libGL-devel glib2-devel libX11-devel libXrandr-devel gperf \
fontconfig-devel cabextract ttmkfdir python python-virtualenv expat-devel \
rpm-build openssl-devel cmake bzip2-devel libXcursor-devel
rpm-build openssl-devel cmake bzip2-devel libXcursor-devel libXmu-devel
pushd /tmp
wget http://corefonts.sourceforge.net/msttcorefonts-2.5-1.spec
rpmbuild -bb msttcorefonts-2.5-1.spec
@@ -48,7 +48,7 @@ popd
On Arch Linux:

``` sh
sudo pacman -S --needed base-devel git python2 python2-virtualenv mesa ttf-font cmake bzip2
sudo pacman -S --needed base-devel git python2 python2-virtualenv mesa ttf-font cmake bzip2 libxmu
```

Cross-compilation for Android:
@@ -58,6 +58,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> {
@@ -102,6 +103,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.
@@ -212,6 +216,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();
});
@@ -395,6 +400,16 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
debug!("constellation got focus message");
self.handle_focus_msg(pipeline_id);
}
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
}
@@ -28,6 +28,7 @@ extern crate net_traits;
extern crate util;
extern crate gleam;
extern crate webdriver_server;
extern crate clipboard;

extern crate libc;
extern crate time;
@@ -229,6 +229,8 @@ pub enum Msg {
GetRootPipeline(Sender<Option<PipelineId>>),
/// Notifies the constellation that this frame has received focus.
FocusMsg(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;
@@ -109,6 +110,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),
@@ -118,7 +120,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(), Some(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(), Some(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)]
pub enum Selection {
@@ -40,6 +43,7 @@ pub struct TextInput {
selection_begin: Option<TextPoint>,
/// Is this a multiline input?
multiline: bool,
constellation_channel: Option<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: Option<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);
}
}

pub fn get_sorted_selection(&self) -> (TextPoint, TextPoint) {
let begin = self.selection_begin.unwrap();
let end = self.edit_point;
@@ -282,10 +296,22 @@ impl TextInput {
self.select_all();
KeyReaction::Nothing
},
"v" if is_control_key(event) => {
let (tx, rx) = channel();
let mut contents = None;
if let Some(ref cc) = self.constellation_channel {
cc.0.send(ConstellationMsg::GetClipboardContents(tx)).unwrap();
contents = Some(rx.recv().unwrap());
}
if let Some(contents) = contents {
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.

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

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.