Skip to content

Commit

Permalink
Merge pull request #3 from rust-windowing/master
Browse files Browse the repository at this point in the history
sync upstream
  • Loading branch information
dzhou121 authored Nov 3, 2023
2 parents 444ecd9 + bcce513 commit 7608048
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 66 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@ Unreleased` header.

# Unreleased

- On Windows, fix so `drag_window` and `drag_resize_window` can be called from another thread.

# 0.29.3

- On Wayland, apply correct scale to `PhysicalSize` passed in `WindowBuilder::with_inner_size` when possible.
- On Wayland, fix `RedrawRequsted` being always sent without decorations and `sctk-adwaita` feature.
- On Wayland, ignore resize requests when the window is fully tiled.
- On Wayland, use `configure_bounds` to constrain `with_inner_size` when compositor wants users to pick size.
- On Windows, fix deadlock when accessing the state during `Cursor{Enter,Leave}`.
- On Windows, add support for `Window::set_transparent`.
- On macOS, fix deadlock when entering a nested event loop from an event handler.
- On macOS, add support for `Window::set_blur`.

# 0.29.2

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "winit"
version = "0.29.2"
version = "0.29.3"
authors = ["The winit contributors", "Pierre Krieger <[email protected]>"]
description = "Cross-platform window creation library."
edition = "2021"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

```toml
[dependencies]
winit = "0.29.2"
winit = "0.29.3"
```

## [Documentation](https://docs.rs/winit)
Expand Down Expand Up @@ -116,7 +116,7 @@ clash.

| winit | ndk-glue |
| :---: | :--------------------------: |
| 0.29.2| `android-activity = "0.5"` |
| 0.29 | `android-activity = "0.5"` |
| 0.28 | `android-activity = "0.4"` |
| 0.27 | `ndk-glue = "0.7"` |
| 0.26 | `ndk-glue = "0.5"` |
Expand Down Expand Up @@ -157,7 +157,7 @@ For more details, refer to these `android-activity` [example applications](https

If your application is currently based on `NativeActivity` via the `ndk-glue` crate and building with `cargo apk` then the minimal changes would be:
1. Remove `ndk-glue` from your `Cargo.toml`
2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.29.2", features = [ "android-native-activity" ] }`
2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.29.3", features = [ "android-native-activity" ] }`
3. Add an `android_main` entrypoint (as above), instead of using the '`[ndk_glue::main]` proc macro from `ndk-macros` (optionally add a dependency on `android_logger` and initialize logging as above).
4. Pass a clone of the `AndroidApp` that your application receives to Winit when building your event loop (as shown above).

Expand Down
13 changes: 8 additions & 5 deletions examples/util/fill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ pub(super) fn fill_window(window: &Window) {
}

GC.with(|gc| {
let size = window.inner_size();
let (Some(width), Some(height)) =
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
else {
return;
};

// Either get the last context used or create a new one.
let mut gc = gc.borrow_mut();
let surface = gc
Expand All @@ -61,13 +68,9 @@ pub(super) fn fill_window(window: &Window) {

// Fill a buffer with a solid color.
const DARK_GRAY: u32 = 0xFF181818;
let size = window.inner_size();

surface
.resize(
NonZeroU32::new(size.width).expect("Width must be greater than zero"),
NonZeroU32::new(size.height).expect("Height must be greater than zero"),
)
.resize(width, height)
.expect("Failed to resize the softbuffer surface");

let mut buffer = surface
Expand Down
3 changes: 2 additions & 1 deletion src/dpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@
//! If `WINIT_X11_SCALE_FACTOR` is set to `randr`, it'll ignore the `Xft.dpi` field and use the
//! XRandR scaling method. Generally speaking, you should try to configure the standard system
//! variables to do what you want before resorting to `WINIT_X11_SCALE_FACTOR`.
//! - **Wayland:** Scale factor is suggested by the the compositor.
//! - **Wayland:** Scale factor is suggested by the compositor for each window individually. The
//! monitor scale factor may differ from the window scale factor.
//! - **iOS:** Scale factors are set by Apple to the value that best suits the device, and range
//! from `1.0` to `3.0`. See [this article][apple_1] and [this article][apple_2] for more
//! information.
Expand Down
6 changes: 5 additions & 1 deletion src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,18 @@ impl MonitorHandle {
self.inner.refresh_rate_millihertz()
}

/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
/// Returns the scale factor of the underlying monitor. To map logical pixels to physical
/// pixels and vice versa, use [`Window::scale_factor`].
///
/// See the [`dpi`](crate::dpi) module for more information.
///
/// ## Platform-specific
///
/// - **X11:** Can be overridden using the `WINIT_X11_SCALE_FACTOR` environment variable.
/// - **Wayland:** May differ from [`Window::scale_factor`].
/// - **Android:** Always returns 1.0.
///
/// [`Window::scale_factor`]: crate::window::Window::scale_factor
#[inline]
pub fn scale_factor(&self) -> f64 {
self.inner.scale_factor()
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/linux/wayland/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ impl<T: 'static> EventLoop<T> {
self.with_state(|state| {
let windows = state.windows.get_mut();
let mut window = windows.get(&window_id).unwrap().lock().unwrap();
window.resize(new_logical_size);
window.request_inner_size(new_logical_size.into());
});
}

Expand Down
16 changes: 6 additions & 10 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,9 @@ impl Window {
.map(|activation_state| activation_state.global().clone());
let display = event_loop_window_target.connection.display();

// XXX The initial scale factor must be 1, but it might cause sizing issues on HiDPI.
let size: LogicalSize<u32> = attributes
let size: Size = attributes
.inner_size
.map(|size| size.to_logical::<u32>(1.))
.unwrap_or((800, 600).into());
.unwrap_or(LogicalSize::new(800., 600.).into());

// We prefer server side decorations, however to not have decorations we ask for client
// side decorations instead.
Expand Down Expand Up @@ -141,7 +139,8 @@ impl Window {
// Set the window title.
window_state.set_title(attributes.title);

// Set the min and max sizes.
// Set the min and max sizes. We must set the hints upon creating a window, so
// we use the default `1.` scaling...
let min_size = attributes.min_inner_size.map(|size| size.to_logical(1.));
let max_size = attributes.max_inner_size.map(|size| size.to_logical(1.));
window_state.set_min_inner_size(min_size);
Expand Down Expand Up @@ -315,12 +314,9 @@ impl Window {
#[inline]
pub fn request_inner_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
let mut window_state = self.window_state.lock().unwrap();
let scale_factor = window_state.scale_factor();
window_state.resize(size.to_logical::<u32>(scale_factor));

let new_size = window_state.request_inner_size(size);
self.request_redraw();

Some(window_state.inner_size().to_physical(scale_factor))
Some(new_size)
}

/// Set the minimum inner size for the window.
Expand Down
95 changes: 81 additions & 14 deletions src/platform_impl/linux/wayland/window/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use sctk::shm::Shm;
use sctk::subcompositor::SubcompositorState;
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;

use crate::dpi::{LogicalPosition, LogicalSize};
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size};
use crate::error::{ExternalError, NotSupportedError};
use crate::event::WindowEvent;
use crate::platform_impl::wayland::event_loop::sink::EventSink;
Expand Down Expand Up @@ -133,6 +133,10 @@ pub struct WindowState {
/// sends `None` for the new size in the configure.
stateless_size: LogicalSize<u32>,

/// Initial window size provided by the user. Removed on the first
/// configure.
initial_size: Option<Size>,

/// The state of the frame callback.
frame_callback_state: FrameCallbackState,

Expand All @@ -153,7 +157,7 @@ impl WindowState {
connection: Connection,
queue_handle: &QueueHandle<WinitState>,
winit_state: &WinitState,
size: LogicalSize<u32>,
initial_size: Size,
window: Window,
theme: Option<Theme>,
) -> Self {
Expand Down Expand Up @@ -194,8 +198,9 @@ impl WindowState {
resizable: true,
scale_factor: 1.,
shm: winit_state.shm.wl_shm().clone(),
size,
stateless_size: size,
size: initial_size.to_logical(1.),
stateless_size: initial_size.to_logical(1.),
initial_size: Some(initial_size),
text_inputs: Vec::new(),
theme,
title: String::default(),
Expand Down Expand Up @@ -253,6 +258,14 @@ impl WindowState {
subcompositor: &Arc<SubcompositorState>,
event_sink: &mut EventSink,
) -> LogicalSize<u32> {
// NOTE: when using fractional scaling or wl_compositor@v6 the scaling
// should be delivered before the first configure, thus apply it to
// properly scale the physical sizes provided by the users.
if let Some(initial_size) = self.initial_size.take() {
self.size = initial_size.to_logical(self.scale_factor());
self.stateless_size = self.size;
}

if configure.decoration_mode == DecorationMode::Client
&& self.frame.is_none()
&& !self.csd_fails
Expand Down Expand Up @@ -297,30 +310,46 @@ impl WindowState {
event_sink.push_window_event(WindowEvent::Occluded(occluded), window_id);
}

let new_size = if let Some(frame) = self.frame.as_mut() {
let (mut new_size, constrain) = if let Some(frame) = self.frame.as_mut() {
// Configure the window states.
frame.update_state(configure.state);

match configure.new_size {
(Some(width), Some(height)) => {
let (width, height) = frame.subtract_borders(width, height);
(
width.map(|w| w.get()).unwrap_or(1),
height.map(|h| h.get()).unwrap_or(1),
(
width.map(|w| w.get()).unwrap_or(1),
height.map(|h| h.get()).unwrap_or(1),
)
.into(),
false,
)
.into()
}
(_, _) if stateless => self.stateless_size,
_ => self.size,
(_, _) if stateless => (self.stateless_size, true),
_ => (self.size, true),
}
} else {
match configure.new_size {
(Some(width), Some(height)) => (width.get(), height.get()).into(),
_ if stateless => self.stateless_size,
_ => self.size,
(Some(width), Some(height)) => ((width.get(), height.get()).into(), false),
_ if stateless => (self.stateless_size, true),
_ => (self.size, true),
}
};

// Apply configure bounds only when compositor let the user decide what size to pick.
if constrain {
let bounds = self.inner_size_bounds(&configure);
new_size.width = bounds
.0
.map(|bound_w| new_size.width.min(bound_w.get()))
.unwrap_or(new_size.width);
new_size.height = bounds
.1
.map(|bound_h| new_size.height.min(bound_h.get()))
.unwrap_or(new_size.height);
}

// XXX Set the configure before doing a resize.
self.last_configure = Some(configure);

Expand All @@ -330,6 +359,30 @@ impl WindowState {
new_size
}

/// Compute the bounds for the inner size of the surface.
fn inner_size_bounds(
&self,
configure: &WindowConfigure,
) -> (Option<NonZeroU32>, Option<NonZeroU32>) {
let configure_bounds = match configure.suggested_bounds {
Some((width, height)) => (NonZeroU32::new(width), NonZeroU32::new(height)),
None => (None, None),
};

if let Some(frame) = self.frame.as_ref() {
let (width, height) = frame.subtract_borders(
configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()),
configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()),
);
(
configure_bounds.0.and(width),
configure_bounds.1.and(height),
)
} else {
configure_bounds
}
}

#[inline]
fn is_stateless(configure: &WindowConfigure) -> bool {
!(configure.is_maximized() || configure.is_fullscreen() || configure.is_tiled())
Expand Down Expand Up @@ -568,8 +621,22 @@ impl WindowState {
}
}

/// Try to resize the window when the user can do so.
pub fn request_inner_size(&mut self, inner_size: Size) -> PhysicalSize<u32> {
if self
.last_configure
.as_ref()
.map(Self::is_stateless)
.unwrap_or(true)
{
self.resize(inner_size.to_logical(self.scale_factor()))
}

self.inner_size().to_physical(self.scale_factor())
}

/// Resize the window to the new inner size.
pub fn resize(&mut self, inner_size: LogicalSize<u32>) {
fn resize(&mut self, inner_size: LogicalSize<u32>) {
self.size = inner_size;

// Update the stateless size.
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/linux/x11/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl XConnection {
return Ok(MonitorHandle::dummy());
}

let default = monitors.get(0).unwrap();
let default = monitors.first().unwrap();

let window_rect = match window_rect {
Some(rect) => rect,
Expand Down
3 changes: 3 additions & 0 deletions src/platform_impl/macos/appkit/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ extern_methods!(
#[method(frame)]
pub(crate) fn frame(&self) -> NSRect;

#[method(windowNumber)]
pub(crate) fn windowNumber(&self) -> NSInteger;

#[method(backingScaleFactor)]
pub(crate) fn backingScaleFactor(&self) -> CGFloat;

Expand Down
9 changes: 9 additions & 0 deletions src/platform_impl/macos/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use core_graphics::{
base::CGError,
display::{CGDirectDisplayID, CGDisplayConfigRef},
};
use objc2::{ffi::NSInteger, runtime::AnyObject};

pub type CGDisplayFadeInterval = f32;
pub type CGDisplayReservationInterval = f32;
Expand Down Expand Up @@ -113,6 +114,14 @@ extern "C" {
pub fn CGDisplayModeCopyPixelEncoding(mode: CGDisplayModeRef) -> CFStringRef;
pub fn CGDisplayModeRetain(mode: CGDisplayModeRef);
pub fn CGDisplayModeRelease(mode: CGDisplayModeRef);

// Wildly used private APIs; Apple uses them for their Terminal.app.
pub fn CGSMainConnectionID() -> *mut AnyObject;
pub fn CGSSetWindowBackgroundBlurRadius(
connection_id: *mut AnyObject,
window_id: NSInteger,
radius: i64,
) -> i32;
}

mod core_video {
Expand Down
Loading

0 comments on commit 7608048

Please sign in to comment.