servo: Merge #5547 - X11 clipboard support (from aweinstock314:x11-clipboard); r=jdm

Manual re-opening of #5479 (since it seems that GitHub disables re-opening with the same number after a rebase).

Source-Repo: https://github.com/servo/servo
Source-Revision: 9974ebb2f969d2de8959fe74844b7410a5acd54e
This commit is contained in:
Avi Weinstock 2015-04-21 14:41:32 -05:00
Родитель d117879670
Коммит b5e3a5f83c
12 изменённых файлов: 104 добавлений и 23 удалений

Просмотреть файл

@ -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,6 +6,8 @@
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;
@ -13,6 +15,7 @@ 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(' ');

12
servo/components/servo/Cargo.lock сгенерированный
Просмотреть файл

@ -79,6 +79,15 @@ dependencies = [
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
]
[[package]]
name = "clipboard"
version = "0.0.1"
source = "git+https://github.com/aweinstock314/rust-x11-clipboard#eae9596e7e407c8b6037b934c1a8e42a309423fd"
dependencies = [
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
]
[[package]]
name = "clock_ticks"
version = "0.0.4"
@ -98,6 +107,7 @@ name = "compositing"
version = "0.0.1"
dependencies = [
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
"clipboard 0.0.1 (git+https://github.com/aweinstock314/rust-x11-clipboard)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
"core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
"devtools_traits 0.0.1",
@ -1077,7 +1087,7 @@ dependencies = [
[[package]]
name = "xlib"
version = "0.1.0"
source = "git+https://github.com/servo/rust-xlib#715e6f9bb3dfcd925996caedeb77aefb31c2bd65"
source = "git+https://github.com/servo/rust-xlib#1a0f3d48fbebf96e2d1bf83ac71309b27f49e0c7"
dependencies = [
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",

12
servo/ports/cef/Cargo.lock сгенерированный
Просмотреть файл

@ -77,6 +77,15 @@ dependencies = [
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
]
[[package]]
name = "clipboard"
version = "0.0.1"
source = "git+https://github.com/aweinstock314/rust-x11-clipboard#eae9596e7e407c8b6037b934c1a8e42a309423fd"
dependencies = [
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
]
[[package]]
name = "clock_ticks"
version = "0.0.4"
@ -96,6 +105,7 @@ name = "compositing"
version = "0.0.1"
dependencies = [
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
"clipboard 0.0.1 (git+https://github.com/aweinstock314/rust-x11-clipboard)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
"core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
"devtools_traits 0.0.1",
@ -1049,7 +1059,7 @@ dependencies = [
[[package]]
name = "xlib"
version = "0.1.0"
source = "git+https://github.com/servo/rust-xlib#715e6f9bb3dfcd925996caedeb77aefb31c2bd65"
source = "git+https://github.com/servo/rust-xlib#1a0f3d48fbebf96e2d1bf83ac71309b27f49e0c7"
dependencies = [
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",

12
servo/ports/gonk/Cargo.lock сгенерированный
Просмотреть файл

@ -71,6 +71,15 @@ dependencies = [
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
]
[[package]]
name = "clipboard"
version = "0.0.1"
source = "git+https://github.com/aweinstock314/rust-x11-clipboard#eae9596e7e407c8b6037b934c1a8e42a309423fd"
dependencies = [
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
]
[[package]]
name = "clock_ticks"
version = "0.0.4"
@ -91,6 +100,7 @@ name = "compositing"
version = "0.0.1"
dependencies = [
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
"clipboard 0.0.1 (git+https://github.com/aweinstock314/rust-x11-clipboard)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
"core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
"devtools_traits 0.0.1",
@ -1035,7 +1045,7 @@ dependencies = [
[[package]]
name = "xlib"
version = "0.1.0"
source = "git+https://github.com/servo/rust-xlib#715e6f9bb3dfcd925996caedeb77aefb31c2bd65"
source = "git+https://github.com/servo/rust-xlib#1a0f3d48fbebf96e2d1bf83ac71309b27f49e0c7"
dependencies = [
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",

Просмотреть файл

@ -12,7 +12,7 @@ use std::borrow::ToOwned;
#[test]
fn test_textinput_delete_char() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None);
textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.delete_char(DeleteDir::Backward);
assert_eq!(textinput.get_content(), "acdefg");
@ -27,7 +27,7 @@ fn test_textinput_delete_char() {
#[test]
fn test_textinput_insert_char() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None);
textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.insert_char('a');
assert_eq!(textinput.get_content(), "abacdefg");
@ -39,7 +39,7 @@ fn test_textinput_insert_char() {
#[test]
fn test_textinput_get_sorted_selection() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None);
textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.adjust_horizontal(2, Selection::Selected);
let (begin, end) = textinput.get_sorted_selection();
@ -56,7 +56,7 @@ fn test_textinput_get_sorted_selection() {
#[test]
fn test_textinput_replace_selection() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None);
textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.adjust_horizontal(2, Selection::Selected);
@ -66,7 +66,7 @@ fn test_textinput_replace_selection() {
#[test]
fn test_textinput_current_line_length() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None);
assert_eq!(textinput.current_line_length(), 3);
textinput.adjust_vertical(1, Selection::NotSelected);
@ -78,7 +78,7 @@ fn test_textinput_current_line_length() {
#[test]
fn test_textinput_adjust_vertical() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None);
textinput.adjust_horizontal(3, Selection::NotSelected);
textinput.adjust_vertical(1, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1);
@ -95,7 +95,7 @@ fn test_textinput_adjust_vertical() {
#[test]
fn test_textinput_adjust_horizontal() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None);
textinput.adjust_horizontal(4, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 0);
@ -115,12 +115,12 @@ fn test_textinput_adjust_horizontal() {
#[test]
fn test_textinput_handle_return() {
let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned());
let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned(), None);
single_line_textinput.adjust_horizontal(3, Selection::NotSelected);
single_line_textinput.handle_return();
assert_eq!(single_line_textinput.get_content(), "abcdef");
let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned());
let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned(), None);
multi_line_textinput.adjust_horizontal(3, Selection::NotSelected);
multi_line_textinput.handle_return();
assert_eq!(multi_line_textinput.get_content(), "abc\ndef");
@ -128,7 +128,7 @@ fn test_textinput_handle_return() {
#[test]
fn test_textinput_select_all() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 0);
@ -139,16 +139,16 @@ fn test_textinput_select_all() {
#[test]
fn test_textinput_get_content() {
let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None);
assert_eq!(single_line_textinput.get_content(), "abcdefg");
let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None);
assert_eq!(multi_line_textinput.get_content(), "abc\nde\nf");
}
#[test]
fn test_textinput_set_content() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None);
assert_eq!(textinput.get_content(), "abc\nde\nf");
textinput.set_content("abc\nf".to_owned());