Skip to content

Commit aad3ed7

Browse files
authored
Fix window drawing when switching X11 workspaces by presenting when expose events occur (#20535)
Closes #18184 Release Notes: - Fix window drawing when switching X11 workspaces, particularly for tiling window managers such as i3wm and XMonad.
1 parent ad3171d commit aad3ed7

File tree

9 files changed

+40
-32
lines changed

9 files changed

+40
-32
lines changed

crates/gpui/src/platform.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,11 @@ impl Tiling {
339339
}
340340
}
341341

342+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
343+
pub(crate) struct RequestFrameOptions {
344+
pub(crate) require_presentation: bool,
345+
}
346+
342347
pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
343348
fn bounds(&self) -> Bounds<Pixels>;
344349
fn is_maximized(&self) -> bool;
@@ -367,7 +372,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
367372
fn zoom(&self);
368373
fn toggle_fullscreen(&self);
369374
fn is_fullscreen(&self) -> bool;
370-
fn on_request_frame(&self, callback: Box<dyn FnMut()>);
375+
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>);
371376
fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> DispatchEventResult>);
372377
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>);
373378
fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>);

crates/gpui/src/platform/linux/wayland/window.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
2626
use crate::scene::Scene;
2727
use crate::{
2828
px, size, AnyWindowHandle, Bounds, Decorations, GPUSpecs, Globals, Modifiers, Output, Pixels,
29-
PlatformDisplay, PlatformInput, Point, PromptLevel, ResizeEdge, ScaledPixels, Size, Tiling,
30-
WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
31-
WindowControls, WindowDecorations, WindowParams,
29+
PlatformDisplay, PlatformInput, Point, PromptLevel, RequestFrameOptions, ResizeEdge,
30+
ScaledPixels, Size, Tiling, WaylandClientStatePtr, WindowAppearance,
31+
WindowBackgroundAppearance, WindowBounds, WindowControls, WindowDecorations, WindowParams,
3232
};
3333

3434
#[derive(Default)]
3535
pub(crate) struct Callbacks {
36-
request_frame: Option<Box<dyn FnMut()>>,
36+
request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
3737
input: Option<Box<dyn FnMut(crate::PlatformInput) -> crate::DispatchEventResult>>,
3838
active_status_change: Option<Box<dyn FnMut(bool)>>,
3939
hover_status_change: Option<Box<dyn FnMut(bool)>>,
@@ -323,7 +323,7 @@ impl WaylandWindowStatePtr {
323323

324324
let mut cb = self.callbacks.borrow_mut();
325325
if let Some(fun) = cb.request_frame.as_mut() {
326-
fun();
326+
fun(Default::default());
327327
}
328328
}
329329

@@ -902,7 +902,7 @@ impl PlatformWindow for WaylandWindow {
902902
self.borrow().fullscreen
903903
}
904904

905-
fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
905+
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) {
906906
self.0.callbacks.borrow_mut().request_frame = Some(callback);
907907
}
908908

crates/gpui/src/platform/linux/x11/client.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ use crate::platform::{LinuxCommon, PlatformWindow};
3838
use crate::{
3939
modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle,
4040
DisplayId, FileDropEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, Pixels,
41-
Platform, PlatformDisplay, PlatformInput, Point, ScaledPixels, ScrollDelta, Size, TouchPhase,
42-
WindowParams, X11Window,
41+
Platform, PlatformDisplay, PlatformInput, Point, RequestFrameOptions, ScaledPixels,
42+
ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
4343
};
4444

4545
use super::{
@@ -531,7 +531,9 @@ impl X11Client {
531531

532532
for window in windows_to_refresh.into_iter() {
533533
if let Some(window) = self.get_window(window) {
534-
window.refresh();
534+
window.refresh(RequestFrameOptions {
535+
require_presentation: true,
536+
});
535537
}
536538
}
537539

@@ -1356,7 +1358,7 @@ impl LinuxClient for X11Client {
13561358
if let Some(window) = state.windows.get(&x_window) {
13571359
let window = window.window.clone();
13581360
drop(state);
1359-
window.refresh();
1361+
window.refresh(Default::default());
13601362
}
13611363
xcb_connection
13621364
};

crates/gpui/src/platform/linux/x11/window.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use crate::{
44
platform::blade::{BladeRenderer, BladeSurfaceConfig},
55
px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GPUSpecs,
66
Modifiers, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
7-
PlatformWindow, Point, PromptLevel, ResizeEdge, ScaledPixels, Scene, Size, Tiling,
8-
WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind,
9-
WindowParams, X11ClientStatePtr,
7+
PlatformWindow, Point, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Scene, Size,
8+
Tiling, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowDecorations,
9+
WindowKind, WindowParams, X11ClientStatePtr,
1010
};
1111

1212
use blade_graphics as gpu;
@@ -227,7 +227,7 @@ struct RawWindow {
227227

228228
#[derive(Default)]
229229
pub struct Callbacks {
230-
request_frame: Option<Box<dyn FnMut()>>,
230+
request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
231231
input: Option<Box<dyn FnMut(PlatformInput) -> crate::DispatchEventResult>>,
232232
active_status_change: Option<Box<dyn FnMut(bool)>>,
233233
hovered_status_change: Option<Box<dyn FnMut(bool)>>,
@@ -830,10 +830,10 @@ impl X11WindowStatePtr {
830830
}
831831
}
832832

833-
pub fn refresh(&self) {
833+
pub fn refresh(&self, request_frame_options: RequestFrameOptions) {
834834
let mut cb = self.callbacks.borrow_mut();
835835
if let Some(ref mut fun) = cb.request_frame {
836-
fun();
836+
fun(request_frame_options);
837837
}
838838
}
839839

@@ -1204,7 +1204,7 @@ impl PlatformWindow for X11Window {
12041204
self.0.state.borrow().fullscreen
12051205
}
12061206

1207-
fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
1207+
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) {
12081208
self.0.callbacks.borrow_mut().request_frame = Some(callback);
12091209
}
12101210

crates/gpui/src/platform/mac/window.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use crate::{
44
ExternalPaths, FileDropEvent, ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers,
55
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
66
PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptLevel,
7-
ScaledPixels, Size, Timer, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
8-
WindowKind, WindowParams,
7+
RequestFrameOptions, ScaledPixels, Size, Timer, WindowAppearance, WindowBackgroundAppearance,
8+
WindowBounds, WindowKind, WindowParams,
99
};
1010
use block::ConcreteBlock;
1111
use cocoa::{
@@ -316,7 +316,7 @@ struct MacWindowState {
316316
native_view: NonNull<Object>,
317317
display_link: Option<DisplayLink>,
318318
renderer: renderer::Renderer,
319-
request_frame_callback: Option<Box<dyn FnMut()>>,
319+
request_frame_callback: Option<Box<dyn FnMut(RequestFrameOptions)>>,
320320
event_callback: Option<Box<dyn FnMut(PlatformInput) -> crate::DispatchEventResult>>,
321321
activate_callback: Option<Box<dyn FnMut(bool)>>,
322322
resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
@@ -1060,7 +1060,7 @@ impl PlatformWindow for MacWindow {
10601060
}
10611061
}
10621062

1063-
fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
1063+
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) {
10641064
self.0.as_ref().lock().request_frame_callback = Some(callback);
10651065
}
10661066

@@ -1617,7 +1617,7 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
16171617
lock.renderer.set_presents_with_transaction(true);
16181618
lock.stop_display_link();
16191619
drop(lock);
1620-
callback();
1620+
callback(Default::default());
16211621

16221622
let mut lock = window_state.lock();
16231623
lock.request_frame_callback = Some(callback);
@@ -1634,7 +1634,7 @@ unsafe extern "C" fn step(view: *mut c_void) {
16341634

16351635
if let Some(mut callback) = lock.request_frame_callback.take() {
16361636
drop(lock);
1637-
callback();
1637+
callback(Default::default());
16381638
window_state.lock().request_frame_callback = Some(callback);
16391639
}
16401640
}

crates/gpui/src/platform/test/window.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{
22
AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DispatchEventResult, GPUSpecs,
33
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
4-
Point, ScaledPixels, Size, TestPlatform, TileId, WindowAppearance, WindowBackgroundAppearance,
5-
WindowBounds, WindowParams,
4+
Point, RequestFrameOptions, ScaledPixels, Size, TestPlatform, TileId, WindowAppearance,
5+
WindowBackgroundAppearance, WindowBounds, WindowParams,
66
};
77
use collections::HashMap;
88
use parking_lot::Mutex;
@@ -221,7 +221,7 @@ impl PlatformWindow for TestWindow {
221221
self.0.lock().is_fullscreen
222222
}
223223

224-
fn on_request_frame(&self, _callback: Box<dyn FnMut()>) {}
224+
fn on_request_frame(&self, _callback: Box<dyn FnMut(RequestFrameOptions)>) {}
225225

226226
fn on_input(&self, callback: Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>) {
227227
self.0.lock().input_callback = Some(callback)

crates/gpui/src/platform/windows/events.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Optio
190190
let mut lock = state_ptr.state.borrow_mut();
191191
if let Some(mut request_frame) = lock.callbacks.request_frame.take() {
192192
drop(lock);
193-
request_frame();
193+
request_frame(Default::default());
194194
state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame);
195195
}
196196
unsafe { ValidateRect(handle, None).ok().log_err() };

crates/gpui/src/platform/windows/window.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ impl WindowsWindowStatePtr {
323323

324324
#[derive(Default)]
325325
pub(crate) struct Callbacks {
326-
pub(crate) request_frame: Option<Box<dyn FnMut()>>,
326+
pub(crate) request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
327327
pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
328328
pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>,
329329
pub(crate) resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
@@ -680,7 +680,7 @@ impl PlatformWindow for WindowsWindow {
680680
self.0.state.borrow().is_fullscreen()
681681
}
682682

683-
fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
683+
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) {
684684
self.0.state.borrow_mut().callbacks.request_frame = Some(callback);
685685
}
686686

crates/gpui/src/window.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ impl Window {
681681
let needs_present = needs_present.clone();
682682
let next_frame_callbacks = next_frame_callbacks.clone();
683683
let last_input_timestamp = last_input_timestamp.clone();
684-
move || {
684+
move |request_frame_options| {
685685
let next_frame_callbacks = next_frame_callbacks.take();
686686
if !next_frame_callbacks.is_empty() {
687687
handle
@@ -695,7 +695,8 @@ impl Window {
695695

696696
// Keep presenting the current scene for 1 extra second since the
697697
// last input to prevent the display from underclocking the refresh rate.
698-
let needs_present = needs_present.get()
698+
let needs_present = request_frame_options.require_presentation
699+
|| needs_present.get()
699700
|| (active.get()
700701
&& last_input_timestamp.get().elapsed() < Duration::from_secs(1));
701702

0 commit comments

Comments
 (0)