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

Implement getting X11 clipboard contents #1805

Merged
merged 4 commits into from
Jul 3, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ You can find its changes [documented below](#070---2021-01-01).
- X11: Add support for transparent windows ([#1803] by [@psychon])
- X11: Added support for `get_monitors` ([#1804] by [@psychon])
- `has_focus` method on `WidgetPod` ([#1825] by [@ForLoveOfCats])
- x11: Add support for getting clipboard contents ([#1805] by [@psychon])

### Changed

Expand Down Expand Up @@ -734,6 +735,7 @@ Last release without a changelog :(
[#1802]: https://github.com/linebender/druid/pull/1802
[#1803]: https://github.com/linebender/druid/pull/1803
[#1804]: https://github.com/linebender/druid/pull/1804
[#1805]: https://github.com/linebender/druid/pull/1805
[#1820]: https://github.com/linebender/druid/pull/1820
[#1825]: https://github.com/linebender/druid/pull/1825

Expand Down
55 changes: 42 additions & 13 deletions druid-shell/src/platform/x11/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

//! X11 implementation of features at the application scope.

use std::cell::RefCell;
use std::collections::HashMap;
use std::cell::{Cell, RefCell};
use std::collections::{HashMap, VecDeque};
use std::convert::{TryFrom, TryInto};
use std::os::unix::io::RawFd;
use std::rc::Rc;
Expand All @@ -27,7 +27,7 @@ use x11rb::protocol::present::ConnectionExt as _;
use x11rb::protocol::render::{self, ConnectionExt as _, Pictformat};
use x11rb::protocol::xfixes::ConnectionExt as _;
use x11rb::protocol::xproto::{
self, ConnectionExt, CreateWindowAux, EventMask, Visualtype, WindowClass,
self, ConnectionExt, CreateWindowAux, EventMask, Timestamp, Visualtype, WindowClass,
};
use x11rb::protocol::Event;
use x11rb::resource_manager::Database as ResourceDb;
Expand Down Expand Up @@ -60,6 +60,8 @@ pub(crate) struct Application {
root_visual_type: Visualtype,
/// The visual for windows with transparent backgrounds, if supported
argb_visual_type: Option<Visualtype>,
/// Pending events that need to be handled later
pending_events: Rc<RefCell<VecDeque<Event>>>,

/// The X11 resource database used to query dpi.
pub(crate) rdb: Rc<ResourceDb>,
Expand All @@ -74,7 +76,7 @@ pub(crate) struct Application {
/// In practice multiple physical monitor drawing areas are present on a single screen.
/// This is achieved via various X server extensions (XRandR/Xinerama/TwinView),
/// with XRandR seeming like the best choice.
screen_num: i32, // Needs a container when no longer const
screen_num: usize, // Needs a container when no longer const
/// The X11 window id of this `Application`.
///
/// This is an input-only non-visual X11 window that is created first during initialization,
Expand All @@ -95,6 +97,8 @@ pub(crate) struct Application {
present_opcode: Option<u8>,
/// Support for the render extension in at least version 0.5?
render_argb32_pictformat_cursor: Option<Pictformat>,
/// Newest timestamp that we received
timestamp: Rc<Cell<Timestamp>>,
}

/// The mutable `Application` state.
Expand Down Expand Up @@ -129,7 +133,7 @@ impl Application {
let (conn, screen_num) = XCBConnection::connect(None)?;
let rdb = Rc::new(ResourceDb::new_from_default(&conn)?);
let connection = Rc::new(conn);
let window_id = Application::create_event_window(&connection, screen_num as i32)?;
let window_id = Application::create_event_window(&connection, screen_num)?;
let state = Rc::new(RefCell::new(State {
quitting: false,
windows: HashMap::new(),
Expand Down Expand Up @@ -210,7 +214,7 @@ impl Application {
Ok(Application {
connection,
rdb,
screen_num: screen_num as i32,
screen_num,
window_id,
state,
idle_read,
Expand All @@ -219,8 +223,10 @@ impl Application {
present_opcode,
root_visual_type,
argb_visual_type,
pending_events: Default::default(),
marker: std::marker::PhantomData,
render_argb32_pictformat_cursor,
timestamp: Rc::new(Cell::new(x11rb::CURRENT_TIME)),
})
}

Expand Down Expand Up @@ -277,12 +283,12 @@ impl Application {
self.render_argb32_pictformat_cursor
}

fn create_event_window(conn: &Rc<XCBConnection>, screen_num: i32) -> Result<u32, Error> {
fn create_event_window(conn: &Rc<XCBConnection>, screen_num: usize) -> Result<u32, Error> {
let id = conn.generate_id()?;
let setup = conn.setup();
let screen = setup
.roots
.get(screen_num as usize)
.get(screen_num)
.ok_or_else(|| anyhow!("invalid screen num: {}", screen_num))?;

// Create the actual window
Expand Down Expand Up @@ -343,7 +349,7 @@ impl Application {

#[inline]
pub(crate) fn screen_num(&self) -> i32 {
self.screen_num
self.screen_num as _
}

#[inline]
Expand Down Expand Up @@ -375,6 +381,21 @@ impl Application {

/// Returns `Ok(true)` if we want to exit the main loop.
fn handle_event(&self, ev: &Event) -> Result<bool, Error> {
if ev.server_generated() {
// Update our latest timestamp
let timestamp = match ev {
Event::KeyPress(ev) => ev.time,
Event::KeyRelease(ev) => ev.time,
Event::ButtonPress(ev) => ev.time,
Event::ButtonRelease(ev) => ev.time,
Event::MotionNotify(ev) => ev.time,
Event::EnterNotify(ev) => ev.time,
Event::LeaveNotify(ev) => ev.time,
Event::PropertyNotify(ev) => ev.time,
_ => self.timestamp.get(),
};
self.timestamp.set(timestamp);
}
match ev {
// NOTE: When adding handling for any of the following events,
// there must be a check against self.window_id
Expand Down Expand Up @@ -514,10 +535,15 @@ impl Application {

self.connection.flush()?;

// Deal with pending events
let mut event = self.pending_events.borrow_mut().pop_front();

// Before we poll on the connection's file descriptor, check whether there are any
// events ready. It could be that XCB has some events in its internal buffers because
// of something that happened during the idle loop.
let mut event = self.connection.poll_for_event()?;
if event.is_none() {
event = self.connection.poll_for_event()?;
}

if event.is_none() {
poll_with_timeout(
Expand Down Expand Up @@ -607,9 +633,12 @@ impl Application {
}

pub fn clipboard(&self) -> Clipboard {
// TODO(x11/clipboard): implement Application::clipboard
tracing::warn!("Application::clipboard is currently unimplemented for X11 platforms.");
Clipboard {}
Clipboard::new(
Rc::clone(&self.connection),
self.screen_num,
Rc::clone(&self.pending_events),
Rc::clone(&self.timestamp),
)
}

pub fn get_locale() -> String {
Expand Down
Loading