Skip to content

Commit 0c079e4

Browse files
authored
Merge branch 'master' into x11-cursors
2 parents 75aba5c + d2e46e6 commit 0c079e4

33 files changed

+431
-217
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ You can find its changes [documented below](#070---2021-01-01).
4242
- Text input handles Delete key ([#1746] by [@bjorn])
4343
- `lens` macro can access nested fields ([#1764] by [@Maan2003])
4444
- X11 backend now supports custom cursors ([#1801] by [@psychon])
45+
- X11: Add support for transparent windows ([#1803] by [@psychon])
46+
- `has_focus` method on `WidgetPod` ([#1825] by [@ForLoveOfCats])
4547

4648
### Changed
4749

48-
- Warn on unhandled Commands ([#1533] by [@Maan2003])
50+
- ~~Warn on unhandled Commands ([#1533] by [@Maan2003])~~ (Reverted in #1813)
4951
- `WindowDesc::new` takes the root widget directly instead of a closure ([#1559] by [@lassipulkkinen])
5052
- Switch to trace-based logging ([#1562] by [@PoignardAzur])
5153
- Spacers in `Flex` are now implemented by calculating the space in `Flex` instead of creating a widget for it ([#1584] by [@JAicewizard])
@@ -68,6 +70,7 @@ You can find its changes [documented below](#070---2021-01-01).
6870
- `Notification`s will not be delivered to the widget that sends them ([#1640] by [@cmyr])
6971
- `TextBox` can handle standard keyboard shortcuts without needing menus ([#1660] by [@cmyr])
7072
- GTK Shell: Prevent mangling of newline characters in clipboard ([#1695] by [@ForLoveOfCats])
73+
- GTK: Replaced call to `std::str::from_utf8_unchecked` with `from_utf8` ([#1820] by [@psychon])
7174
- Use correct fill rule when rendering SVG paths ([#1606] by [@SecondFlight])
7275
- Correctly capture and use stroke properties when rendering SVG paths ([#1647] by [@SecondFlight])
7376
- focus-chain now only includes non hidden (`should_propagate_to_hidden()` on `Event` and `Lifecylce`) widgets ([#1724] by [@xarvic])
@@ -728,6 +731,9 @@ Last release without a changelog :(
728731
[#1787]: https://github.com/linebender/druid/pull/1787
729732
[#1801]: https://github.com/linebender/druid/pull/1800
730733
[#1802]: https://github.com/linebender/druid/pull/1802
734+
[#1803]: https://github.com/linebender/druid/pull/1803
735+
[#1820]: https://github.com/linebender/druid/pull/1820
736+
[#1825]: https://github.com/linebender/druid/pull/1825
731737

732738
[Unreleased]: https://github.com/linebender/druid/compare/v0.7.0...master
733739
[0.7.0]: https://github.com/linebender/druid/compare/v0.6.0...v0.7.0

druid-derive/src/attr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub enum FieldIdent {
5252
impl FieldIdent {
5353
pub fn unwrap_named(&self) -> syn::Ident {
5454
if let FieldIdent::Named(s) = self {
55-
syn::Ident::new(&s, Span::call_site())
55+
syn::Ident::new(s, Span::call_site())
5656
} else {
5757
panic!("Unwrap named called on unnamed FieldIdent");
5858
}
@@ -272,7 +272,7 @@ impl Field<LensAttrs> {
272272
impl<Attrs> Field<Attrs> {
273273
pub fn ident_tokens(&self) -> TokenTree {
274274
match self.ident {
275-
FieldIdent::Named(ref s) => Ident::new(&s, Span::call_site()).into(),
275+
FieldIdent::Named(ref s) => Ident::new(s, Span::call_site()).into(),
276276
FieldIdent::Unnamed(num) => Literal::usize_unsuffixed(num).into(),
277277
}
278278
}

druid-derive/src/data.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ fn derive_enum(
8787
let impl_generics = generics_bounds(&input.generics);
8888
let (_, ty_generics, where_clause) = &input.generics.split_for_impl();
8989

90-
if is_c_style_enum(&s) {
90+
if is_c_style_enum(s) {
9191
let res = quote! {
9292
impl<#impl_generics> ::druid::Data for #ident #ty_generics #where_clause {
9393
fn same(&self, other: &Self) -> bool { self == other }

druid-derive/src/lens.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ fn derive_struct(input: &syn::DeriveInput) -> Result<proc_macro2::TokenStream, s
154154

155155
let associated_items = fields.iter().filter(|f| !f.attrs.ignore).map(|f| {
156156
let field_name = &f.ident.unwrap_named();
157-
let lens_field_name = f.attrs.lens_name_override.as_ref().unwrap_or(&field_name);
157+
let lens_field_name = f.attrs.lens_name_override.as_ref().unwrap_or(field_name);
158158

159159
quote! {
160160
/// Lens for the corresponding field.

druid-shell/src/platform/gtk/clipboard.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ impl Clipboard {
6464
let idx = idx as usize;
6565
if idx < formats.len() {
6666
let item = &formats[idx];
67-
if item.identifier == ClipboardFormat::TEXT {
68-
sel.set_text(unsafe { std::str::from_utf8_unchecked(&item.data) });
67+
if let (ClipboardFormat::TEXT, Ok(data)) =
68+
(item.identifier, std::str::from_utf8(&item.data))
69+
{
70+
sel.set_text(data);
6971
} else {
7072
let atom = Atom::intern(item.identifier);
7173
let stride = 8;
@@ -130,7 +132,8 @@ impl Clipboard {
130132
let targets = clipboard.wait_for_targets().unwrap_or_default();
131133
targets
132134
.iter()
133-
.map(|atom| unsafe { format!("{} ({})", atom.name(), atom.value()) })
135+
// SAFETY: Atom::value() is 'self.0 as usize'. No idea why that is unsafe.
136+
.map(|atom| format!("{} ({})", atom.name(), unsafe { atom.value() }))
134137
.collect()
135138
}
136139
}

druid-shell/src/platform/gtk/window.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ impl WindowBuilder {
430430
// region, because there might be parts of the drawing area that were
431431
// invalidated by external forces).
432432
let alloc = widget.get_allocation();
433-
context.set_source_surface(&surface, 0.0, 0.0);
433+
context.set_source_surface(surface, 0.0, 0.0);
434434
context.rectangle(0.0, 0.0, alloc.width as f64, alloc.height as f64);
435435
context.fill();
436436
});
@@ -1170,7 +1170,7 @@ impl WindowHandle {
11701170
old_menubar.deactivate();
11711171
vbox.remove(first_child);
11721172
}
1173-
let menubar = menu.into_gtk_menubar(&self, &accel_group);
1173+
let menubar = menu.into_gtk_menubar(self, &accel_group);
11741174
vbox.pack_start(&menubar, false, false, 0);
11751175
menubar.show_all();
11761176
}
@@ -1234,7 +1234,7 @@ impl IdleHandle {
12341234
fn run_idle(state: &Arc<WindowState>) -> glib::source::Continue {
12351235
util::assert_main_thread();
12361236
let result = state.with_handler(|handler| {
1237-
let queue: Vec<_> = std::mem::replace(&mut state.idle_queue.lock().unwrap(), Vec::new());
1237+
let queue: Vec<_> = std::mem::take(&mut state.idle_queue.lock().unwrap());
12381238

12391239
for item in queue {
12401240
match item {

druid-shell/src/platform/x11/application.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ use x11rb::connection::{Connection, RequestConnection};
2626
use x11rb::protocol::present::ConnectionExt as _;
2727
use x11rb::protocol::render::{self, ConnectionExt as _, Pictformat};
2828
use x11rb::protocol::xfixes::ConnectionExt as _;
29-
use x11rb::protocol::xproto::{self, ConnectionExt, CreateWindowAux, EventMask, WindowClass};
29+
use x11rb::protocol::xproto::{
30+
self, ConnectionExt, CreateWindowAux, EventMask, Visualtype, WindowClass,
31+
};
3032
use x11rb::protocol::Event;
3133
use x11rb::resource_manager::Database as ResourceDb;
3234
use x11rb::xcb_ffi::XCBConnection;
@@ -52,6 +54,11 @@ pub(crate) struct Application {
5254
/// `druid_shell::WindowHandle` to be `!Send` and `!Sync`.
5355
marker: std::marker::PhantomData<*mut XCBConnection>,
5456

57+
/// The type of visual used by the root window
58+
root_visual_type: Visualtype,
59+
/// The visual for windows with transparent backgrounds, if supported
60+
argb_visual_type: Option<Visualtype>,
61+
5562
/// The X11 resource database used to query dpi.
5663
pub(crate) rdb: Rc<ResourceDb>,
5764
pub(crate) cursors: Cursors,
@@ -189,6 +196,15 @@ impl Application {
189196
col_resize: load_cursor("col-resize"),
190197
};
191198

199+
let screen = connection
200+
.setup()
201+
.roots
202+
.get(screen_num as usize)
203+
.ok_or_else(|| anyhow!("Invalid screen num: {}", screen_num))?;
204+
let root_visual_type = util::get_visual_from_screen(&screen)
205+
.ok_or_else(|| anyhow!("Couldn't get visual from screen"))?;
206+
let argb_visual_type = util::get_argb_visual_type(&*connection, &screen)?;
207+
192208
Ok(Application {
193209
connection,
194210
rdb,
@@ -199,6 +215,8 @@ impl Application {
199215
cursors,
200216
idle_write,
201217
present_opcode,
218+
root_visual_type,
219+
argb_visual_type,
202220
marker: std::marker::PhantomData,
203221
render_argb32_pictformat_cursor,
204222
})
@@ -326,6 +344,33 @@ impl Application {
326344
self.screen_num
327345
}
328346

347+
#[inline]
348+
pub(crate) fn argb_visual_type(&self) -> Option<Visualtype> {
349+
// Check if a composite manager is running
350+
let atom_name = format!("_NET_WM_CM_S{}", self.screen_num);
351+
let owner = self
352+
.connection
353+
.intern_atom(false, atom_name.as_bytes())
354+
.ok()
355+
.and_then(|cookie| cookie.reply().ok())
356+
.map(|reply| reply.atom)
357+
.and_then(|atom| self.connection.get_selection_owner(atom).ok())
358+
.and_then(|cookie| cookie.reply().ok())
359+
.map(|reply| reply.owner);
360+
361+
if Some(x11rb::NONE) == owner {
362+
tracing::debug!("_NET_WM_CM_Sn selection is unowned, not providing ARGB visual");
363+
None
364+
} else {
365+
self.argb_visual_type
366+
}
367+
}
368+
369+
#[inline]
370+
pub(crate) fn root_visual_type(&self) -> Visualtype {
371+
self.root_visual_type
372+
}
373+
329374
/// Returns `Ok(true)` if we want to exit the main loop.
330375
fn handle_event(&self, ev: &Event) -> Result<bool, Error> {
331376
match ev {

druid-shell/src/platform/x11/util.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ use std::rc::Rc;
1919
use std::time::Instant;
2020

2121
use anyhow::{anyhow, Error};
22+
use x11rb::connection::RequestConnection;
23+
use x11rb::errors::ReplyError;
2224
use x11rb::protocol::randr::{ConnectionExt, ModeFlag};
23-
use x11rb::protocol::xproto::{Screen, Visualtype, Window};
25+
use x11rb::protocol::render::{self, ConnectionExt as _};
26+
use x11rb::protocol::xproto::{Screen, Visualid, Visualtype, Window};
2427
use x11rb::xcb_ffi::XCBConnection;
2528

2629
use crate::window::TimerToken;
@@ -69,17 +72,76 @@ pub fn refresh_rate(conn: &Rc<XCBConnection>, window_id: Window) -> Option<f64>
6972
}
7073

7174
// Apparently you have to get the visualtype this way :|
72-
pub fn get_visual_from_screen(screen: &Screen) -> Option<Visualtype> {
75+
fn find_visual_from_screen(screen: &Screen, visual_id: u32) -> Option<Visualtype> {
7376
for depth in &screen.allowed_depths {
7477
for visual in &depth.visuals {
75-
if visual.visual_id == screen.root_visual {
78+
if visual.visual_id == visual_id {
7679
return Some(*visual);
7780
}
7881
}
7982
}
8083
None
8184
}
8285

86+
pub fn get_visual_from_screen(screen: &Screen) -> Option<Visualtype> {
87+
find_visual_from_screen(screen, screen.root_visual)
88+
}
89+
90+
pub fn get_argb_visual_type(
91+
conn: &XCBConnection,
92+
screen: &Screen,
93+
) -> Result<Option<Visualtype>, ReplyError> {
94+
fn find_visual_for_format(
95+
reply: &render::QueryPictFormatsReply,
96+
id: render::Pictformat,
97+
) -> Option<Visualid> {
98+
let find_in_depth = |depth: &render::Pictdepth| {
99+
depth
100+
.visuals
101+
.iter()
102+
.find(|visual| visual.format == id)
103+
.map(|visual| visual.visual)
104+
};
105+
let find_in_screen =
106+
|screen: &render::Pictscreen| screen.depths.iter().find_map(find_in_depth);
107+
reply.screens.iter().find_map(find_in_screen)
108+
}
109+
110+
// Getting a visual is already funny, but finding the ARGB32 visual is even more fun.
111+
// RENDER has picture formats. Each format corresponds to a visual. Thus, we first find the
112+
// right picture format, then find the corresponding visual id, then the Visualtype.
113+
if conn
114+
.extension_information(render::X11_EXTENSION_NAME)?
115+
.is_none()
116+
{
117+
// RENDER not supported
118+
Ok(None)
119+
} else {
120+
let pict_formats = conn.render_query_pict_formats()?.reply()?;
121+
// Find the ARGB32 standard format
122+
let res = pict_formats
123+
.formats
124+
.iter()
125+
.find(|format| {
126+
format.type_ == render::PictType::DIRECT
127+
&& format.depth == 32
128+
&& format.direct.red_shift == 16
129+
&& format.direct.red_mask == 0xff
130+
&& format.direct.green_shift == 8
131+
&& format.direct.green_mask == 0xff
132+
&& format.direct.blue_shift == 0
133+
&& format.direct.blue_mask == 0xff
134+
&& format.direct.alpha_shift == 24
135+
&& format.direct.alpha_mask == 0xff
136+
})
137+
// Now find the corresponding visual ID
138+
.and_then(|format| find_visual_for_format(&pict_formats, format.id))
139+
// And finally, we can find the visual
140+
.and_then(|visual_id| find_visual_from_screen(screen, visual_id));
141+
Ok(res)
142+
}
143+
}
144+
83145
macro_rules! log_x11 {
84146
($val:expr) => {
85147
if let Err(e) = $val {

0 commit comments

Comments
 (0)