Skip to content

Commit

Permalink
Merge branch 'master' into x11-clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
maan2003 authored Jun 30, 2021
2 parents 9693fa5 + e2bb4fb commit 86258ec
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 51 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ You can find its changes [documented below](#070---2021-01-01).
- `lens` macro can access nested fields ([#1764] by [@Maan2003])
- X11 backend now supports custom cursors ([#1801] by [@psychon])
- X11: Add support for transparent windows ([#1803] by [@psychon])
- X11: Added support for `get_monitors` ([#1804] by [@psychon])
- x11: Add support for getting clipboard contents ([#1805] by [@psychon])
- `has_focus` method on `WidgetPod` ([#1825] by [@ForLoveOfCats])

Expand Down Expand Up @@ -733,6 +734,7 @@ Last release without a changelog :(
[#1801]: https://github.com/linebender/druid/pull/1800
[#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
2 changes: 1 addition & 1 deletion docs/book_examples/src/data_md.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![allow(clippy::clippy::rc_buffer)]
#![allow(clippy::rc_buffer)]

#[derive(Clone, PartialEq)]
struct DateTime(std::time::Instant);
Expand Down
34 changes: 11 additions & 23 deletions druid-derive/tests/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,36 +60,30 @@ fn test_data_derive_same() {

let singletuple = SingleTupleStruct(true);
assert!(singletuple.same(&singletuple));
assert_eq!(false, singletuple.same(&SingleTupleStruct(false)));
assert!(!singletuple.same(&SingleTupleStruct(false)));

let multituple = MultiTupleStruct(false, 33, "Test".to_string());
assert!(multituple.same(&multituple));
assert_eq!(
false,
multituple.same(&MultiTupleStruct(true, 33, "Test".to_string()))
);
assert!(!multituple.same(&MultiTupleStruct(true, 33, "Test".to_string())));

let empty_field = EmptyFieldStruct {};
assert!(empty_field.same(&empty_field));

let singlefield = SingleFieldStruct { a: true };
assert!(singlefield.same(&singlefield));
assert_eq!(false, singlefield.same(&SingleFieldStruct { a: false }));
assert!(!singlefield.same(&SingleFieldStruct { a: false }));

let multifield = MultiFieldStruct {
a: false,
b: 33,
c: "Test".to_string(),
};
assert!(multifield.same(&multifield));
assert_eq!(
false,
multifield.same(&MultiFieldStruct {
a: false,
b: 33,
c: "Fail".to_string()
})
);
assert!(!multifield.same(&MultiFieldStruct {
a: false,
b: 33,
c: "Fail".to_string()
}));

#[derive(Clone, Data)]
struct Value(u32);
Expand All @@ -98,19 +92,13 @@ fn test_data_derive_same() {

let v = TypeParamForUserTraitStruct { a: Value(1) };
assert!(v.same(&v));
assert_eq!(false, v.same(&TypeParamForUserTraitStruct { a: Value(2) }));
assert!(!v.same(&TypeParamForUserTraitStruct { a: Value(2) }));

let v = TypeParamForUserTraitWithWhereClauseStruct { b: Value(3) };
assert!(v.same(&v));
assert_eq!(
false,
v.same(&TypeParamForUserTraitWithWhereClauseStruct { b: Value(6) })
);
assert!(!v.same(&TypeParamForUserTraitWithWhereClauseStruct { b: Value(6) }));

let v = TypeParamForUserTraitAndLifetimeEnum::V1(Value(10));
assert!(v.same(&v));
assert_eq!(
false,
v.same(&TypeParamForUserTraitAndLifetimeEnum::V1(Value(12)))
);
assert!(!v.same(&TypeParamForUserTraitAndLifetimeEnum::V1(Value(12))));
}
37 changes: 34 additions & 3 deletions druid-shell/src/platform/gtk/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ pub(crate) struct WindowState {
click_counter: ClickCounter,
active_text_input: Cell<Option<TextFieldToken>>,
deferred_queue: RefCell<Vec<DeferredOp>>,

request_animation: Cell<bool>,
in_draw: Cell<bool>,
}

#[derive(Clone, PartialEq)]
Expand Down Expand Up @@ -296,6 +299,8 @@ impl WindowBuilder {
click_counter: ClickCounter::default(),
active_text_input: Cell::new(None),
deferred_queue: RefCell::new(Vec::new()),
request_animation: Cell::new(false),
in_draw: Cell::new(false),
});

self.app
Expand Down Expand Up @@ -361,6 +366,27 @@ impl WindowBuilder {
);
}

win_state
.drawing_area
.connect_realize(clone!(handle => move |drawing_area| {
if let Some(clock) = drawing_area.get_frame_clock() {
clock.connect_before_paint(clone!(handle => move |_clock|{
if let Some(state) = handle.state.upgrade() {
state.in_draw.set(true);
}
}));
clock.connect_after_paint(clone!(handle => move |_clock|{
if let Some(state) = handle.state.upgrade() {
state.in_draw.set(false);
if state.request_animation.get() {
state.request_animation.set(false);
state.drawing_area.queue_draw();
}
}
}));
}
}));

win_state.drawing_area.connect_draw(clone!(handle => move |widget, context| {
if let Some(state) = handle.state.upgrade() {
let mut scale = state.scale.get();
Expand Down Expand Up @@ -780,7 +806,11 @@ impl WindowState {
/// Queues a call to `prepare_paint` and `paint`, but without marking any region for
/// invalidation.
fn request_anim_frame(&self) {
self.window.queue_draw();
if self.in_draw.get() {
self.request_animation.set(true);
} else {
self.drawing_area.queue_draw()
}
}

/// Invalidates a rectangle, given in display points.
Expand Down Expand Up @@ -1156,7 +1186,6 @@ impl WindowHandle {
pub fn set_menu(&self, menu: Menu) {
if let Some(state) = self.state.upgrade() {
let window = &state.window;

let accel_group = AccelGroup::new();
window.add_accel_group(&accel_group);

Expand All @@ -1168,7 +1197,7 @@ impl WindowHandle {
let first_child = &vbox.get_children()[0];
if let Some(old_menubar) = first_child.downcast_ref::<gtk::MenuBar>() {
old_menubar.deactivate();
vbox.remove(first_child);
vbox.remove(old_menubar);
}
let menubar = menu.into_gtk_menubar(self, &accel_group);
vbox.pack_start(&menubar, false, false, 0);
Expand Down Expand Up @@ -1209,6 +1238,7 @@ impl IdleHandle {
{
let mut queue = self.idle_queue.lock().unwrap();
if let Some(state) = self.state.upgrade() {
#[allow(clippy::branches_sharing_code)]
if queue.is_empty() {
queue.push(IdleKind::Callback(Box::new(callback)));
glib::idle_add(move || run_idle(&state));
Expand All @@ -1221,6 +1251,7 @@ impl IdleHandle {
pub fn add_idle_token(&self, token: IdleToken) {
let mut queue = self.idle_queue.lock().unwrap();
if let Some(state) = self.state.upgrade() {
#[allow(clippy::branches_sharing_code)]
if queue.is_empty() {
queue.push(IdleKind::Token(token));
glib::idle_add(move || run_idle(&state));
Expand Down
2 changes: 1 addition & 1 deletion druid-shell/src/platform/mac/dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

//! File open/save dialogs, macOS implementation.
#![allow(non_upper_case_globals, clippy::clippy::upper_case_acronyms)]
#![allow(non_upper_case_globals, clippy::upper_case_acronyms)]

use std::ffi::OsString;

Expand Down
4 changes: 3 additions & 1 deletion druid-shell/src/platform/mac/text_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// apple's documentation on text editing is also very helpful:
// https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TextEditing/TextEditing.html#//apple_ref/doc/uid/TP40009459-CH3-SW3

#![allow(clippy::clippy::upper_case_acronyms, non_snake_case)]
#![allow(clippy::upper_case_acronyms, non_snake_case)]

use std::ffi::c_void;
use std::ops::Range;
Expand Down Expand Up @@ -65,6 +65,8 @@ unsafe impl objc::Encode for NSRange {
}
}

// BOOL is i8 on x86, but bool on aarch64
#[cfg_attr(target_arch = "aarch64", allow(clippy::useless_conversion))]
pub extern "C" fn has_marked_text(this: &mut Object, _: Sel) -> BOOL {
with_edit_lock_from_window(this, false, |edit_lock| {
edit_lock.composition_range().is_some()
Expand Down
5 changes: 1 addition & 4 deletions druid-shell/src/platform/mac/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,10 +897,7 @@ extern "C" fn run_idle(this: &mut Object, _: Sel) {
let view_state: *mut c_void = *this.get_ivar("viewState");
&mut *(view_state as *mut ViewState)
};
let queue: Vec<_> = mem::replace(
&mut view_state.idle_queue.lock().expect("queue"),
Vec::new(),
);
let queue: Vec<_> = mem::take(&mut view_state.idle_queue.lock().expect("queue"));
for item in queue {
match item {
IdleKind::Callback(it) => it.call(&mut *view_state.handler),
Expand Down
2 changes: 1 addition & 1 deletion druid-shell/src/platform/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2126,7 +2126,7 @@ impl WindowHandle {

fn take_idle_queue(&self) -> Vec<IdleKind> {
if let Some(w) = self.state.upgrade() {
mem::replace(&mut w.idle_queue.lock().unwrap(), Vec::new())
mem::take(&mut w.idle_queue.lock().unwrap())
} else {
Vec::new()
}
Expand Down
138 changes: 136 additions & 2 deletions druid-shell/src/platform/x11/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,143 @@

//! X11 Monitors and Screen information.
use x11rb::connection::Connection;
use x11rb::errors::ReplyOrIdError;
use x11rb::protocol::randr::{self, ConnectionExt as _, Crtc};
use x11rb::protocol::xproto::{Screen, Timestamp};

use crate::kurbo::Rect;
use crate::screen::Monitor;

fn monitor<Pos>(primary: bool, (x, y): (Pos, Pos), (width, height): (u16, u16)) -> Monitor
where
Pos: Into<i32>,
{
let rect = Rect::from_points(
(x.into() as f64, y.into() as f64),
(width as f64, height as f64),
);
// TODO: Support for work_rect. It's complicated...
Monitor::new(primary, rect, rect)
}

pub(crate) fn get_monitors() -> Vec<Monitor> {
tracing::warn!("Screen::get_monitors() is currently unimplemented for X11 platforms.");
Vec::new()
let result = if let Some(app) = crate::Application::try_global() {
let app = app.platform_app;
get_monitors_impl(app.connection().as_ref(), app.screen_num() as usize)
} else {
let (conn, screen_num) = match x11rb::connect(None) {
Ok(res) => res,
Err(err) => {
tracing::error!("Error in Screen::get_monitors(): {:?}", err);
return Vec::new();
}
};
get_monitors_impl(&conn, screen_num)
};
match result {
Ok(monitors) => monitors,
Err(err) => {
tracing::error!("Error in Screen::get_monitors(): {:?}", err);
Vec::new()
}
}
}

fn get_monitors_impl(
conn: &impl Connection,
screen_num: usize,
) -> Result<Vec<Monitor>, ReplyOrIdError> {
let screen = &conn.setup().roots[screen_num];

if conn
.extension_information(randr::X11_EXTENSION_NAME)?
.is_none()
{
return get_monitors_core(screen);
}

// Monitor support was added in RandR 1.5
let version = conn.randr_query_version(1, 5)?.reply()?;
match (version.major_version, version.minor_version) {
(major, _) if major >= 2 => get_monitors_randr_monitors(conn, screen),
(1, minor) if minor >= 5 => get_monitors_randr_monitors(conn, screen),
(1, minor) if minor >= 3 => get_monitors_randr_screen_resources_current(conn, screen),
(1, minor) if minor >= 2 => get_monitors_randr_screen_resources(conn, screen),
_ => get_monitors_core(screen),
}
}

fn get_monitors_core(screen: &Screen) -> Result<Vec<Monitor>, ReplyOrIdError> {
Ok(vec![monitor(
true,
(0, 0),
(screen.width_in_pixels, screen.height_in_pixels),
)])
}

fn get_monitors_randr_monitors(
conn: &impl Connection,
screen: &Screen,
) -> Result<Vec<Monitor>, ReplyOrIdError> {
let result = conn
.randr_get_monitors(screen.root, true)?
.reply()?
.monitors
.iter()
.map(|info| monitor(info.primary, (info.x, info.y), (info.width, info.height)))
.collect();
Ok(result)
}

fn get_monitors_randr_screen_resources_current(
conn: &impl Connection,
screen: &Screen,
) -> Result<Vec<Monitor>, ReplyOrIdError> {
let reply = conn
.randr_get_screen_resources_current(screen.root)?
.reply()?;
get_monitors_randr_crtcs_timestamp(conn, &reply.crtcs, reply.config_timestamp)
}

fn get_monitors_randr_screen_resources(
conn: &impl Connection,
screen: &Screen,
) -> Result<Vec<Monitor>, ReplyOrIdError> {
let reply = conn.randr_get_screen_resources(screen.root)?.reply()?;
get_monitors_randr_crtcs_timestamp(conn, &reply.crtcs, reply.config_timestamp)
}

// This function first sends a number of requests, collect()ing them into a Vec and then gets the
// replies. This saves round-trips. Without the collect(), there would be one round-trip per CRTC.
#[allow(clippy::needless_collect)]
fn get_monitors_randr_crtcs_timestamp(
conn: &impl Connection,
crtcs: &[Crtc],
config_timestamp: Timestamp,
) -> Result<Vec<Monitor>, ReplyOrIdError> {
// Request information about all CRTCs
let requests = crtcs
.iter()
.map(|&crtc| conn.randr_get_crtc_info(crtc, config_timestamp))
.collect::<Vec<_>>();

// Deal with CRTC information
let mut result = Vec::new();
for request in requests.into_iter() {
let reply = request?.reply()?;
if reply.width != 0 && reply.height != 0 {
// First CRTC is assumed to be the primary output
let primary = result.is_empty();
result.push(monitor(
primary,
(reply.x, reply.y),
(reply.width, reply.height),
));
}
}
// TODO: I think we need to deduplicate monitors. In clone mode, each "clone" appears as its
// own monitor otherwise.

Ok(result)
}
4 changes: 2 additions & 2 deletions druid/examples/value_formatting/src/formatters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl Formatter<PostalCode> for CanadianPostalCodeFormatter {
}
}

#[allow(clippy::clippy::many_single_char_names, clippy::clippy::match_ref_pats)]
#[allow(clippy::many_single_char_names, clippy::match_ref_pats)]
fn value(&self, input: &str) -> Result<PostalCode, ValidationError> {
match input.as_bytes() {
&[a, b, c, d, e, f] => PostalCode::from_bytes([a, b, c, d, e, f]),
Expand Down Expand Up @@ -298,7 +298,7 @@ impl PostalCode {
}
}

#[allow(clippy::clippy::many_single_char_names)]
#[allow(clippy::many_single_char_names)]
impl std::fmt::Display for PostalCode {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let [a, b, c, d, e, g] = self.chars;
Expand Down
Loading

0 comments on commit 86258ec

Please sign in to comment.