Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 0 additions & 14 deletions rivet/runtime/windows/src/chromium/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,6 @@ impl View {
}
}

/// The parent of a live view of the loaded build, when its parent pointer holds a view of the
/// browser module: an object whose first word points into the module. `None` for a root, an
/// unreadable place or a build that records no bounds offset.
pub(crate) unsafe fn parent_of(view: usize) -> Option<usize> {
let offset = View::parent_offset(crate::builds::get().layout.view_bounds_offset)?;
if !crate::chromium::memory::readable(view.checked_add(offset)?, 8) {
return None;
}
let parent = View::at(view).parent_address(offset);
let image = crate::chromium::image::recorded()?;
let table = crate::chromium::memory::read_word(parent)?;
(table > image.base && table < image.base + image.size).then_some(parent)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
5 changes: 0 additions & 5 deletions rivet/runtime/windows/src/features/frame_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,11 +1018,6 @@ pub unsafe fn relayout(window: HWND) -> bool {
let layout_immediately: unsafe extern "system" fn(*mut c_void) =
std::mem::transmute(base + bv().layout_immediately);
layout_immediately(view as *mut c_void);
// The non-client view above the frame view gives the client view the bounds the frame
// view leaves it, so a new appbar width moves the page only when it lays out too.
if let Some(parent) = crate::chromium::view::parent_of(view) {
layout_immediately(parent as *mut c_void);
}
true
}
None => false,
Expand Down
108 changes: 103 additions & 5 deletions rivet/runtime/windows/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2028,11 +2028,6 @@ unsafe fn sync_strip(window: HWND) {
unsafe fn relayout(window: HWND) {
// The frame view lays out again on request, which also works for a maximized window.
crate::features::vertical_tabs::invalidate_strip(window);
// The frame view lays its client view out again only when the client view's bounds change,
// and a new appbar width can leave them as they were while the page area must move. The
// browser view lays its page area out again here, whether or not the frame view's own layout
// is recorded, as on Brave and Whale the page otherwise waits for the next input.
crate::hooks::page_area::relayout(window);
if frame_layout::relayout(window) {
if is_waiting(window) {
crate::trace::trace("attach: asked the frame view to lay out again");
Expand Down Expand Up @@ -2146,16 +2141,82 @@ unsafe fn nudge(window: HWND, why: &str) -> bool {
/// Hides the docked appbar so the page takes its width, or docks it again.
unsafe fn toggle_appbar(window: HWND) {
close_menu(window);
let before = frame_layout::panel_bounds(window).map(|panel| panel.x);
edit_layout(window, |layout| layout.toggle());
crate::trace::trace(&format!("appbar: hidden {}", layout_of(window).collapsed));
sync_strip(window);
SLIDE.with(|slides| slides.borrow_mut().remove(&(window as isize)));
KillTimer(window, PEEK_TIMER);
relayout(window);
let after = frame_layout::panel_bounds(window).map(|panel| panel.x);
if needs_size_nudge(before, after, sizing_state(window)) {
nudge_size(window, before, after);
}
// The panel moves with the appbar, and the top bar with it.
request_bar_paint(window);
}

/// Whether a fold or show must be laid out by a size change: the browser laid the window out
/// again, yet its page panel did not move, as Brave and Whale keep the client area they laid out
/// until the window's size changes. Only a window of its own size is resized: never a minimized,
/// maximized, snapped or fullscreen one.
fn needs_size_nudge(before: Option<i32>, after: Option<i32>, state: NudgeState) -> bool {
before.is_some()
&& before == after
&& !state.minimized
&& !state.maximized
&& !state.snapped
&& !state.fullscreen
}

/// The window's size state, for a size change after a fold or show.
unsafe fn sizing_state(window: HWND) -> NudgeState {
use windows_sys::Win32::UI::WindowsAndMessaging::IsWindowArranged;
NudgeState {
minimized: IsIconic(window) != 0,
maximized: IsZoomed(window) != 0,
snapped: IsWindowArranged(window) != 0,
fullscreen: GetWindowLongPtrW(window, GWL_STYLE) as u32 & WS_THICKFRAME == 0,
..NudgeState::default()
}
}

/// Shrinks the window by one pixel without drawing and puts its exact rect back, which lays the
/// browser's root view out at once, and traces what happened.
unsafe fn nudge_size(window: HWND, before: Option<i32>, after: Option<i32>) {
use windows_sys::Win32::UI::WindowsAndMessaging::{GetWindowRect, SWP_NOREDRAW};
let mut rect: RECT = std::mem::zeroed();
GetWindowRect(window, &mut rect);
let (width, height) = (rect.right - rect.left, rect.bottom - rect.top);
SetWindowPos(
window,
std::ptr::null_mut(),
0,
0,
width,
height - 1,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW,
);
SetWindowPos(
window,
std::ptr::null_mut(),
rect.left,
rect.top,
width,
height,
SWP_NOZORDER | SWP_NOACTIVATE,
);
let mut now: RECT = std::mem::zeroed();
GetWindowRect(window, &mut now);
let restored = (now.left, now.top, now.right, now.bottom)
== (rect.left, rect.top, rect.right, rect.bottom);
crate::trace::trace(&format!(
"appbar: the panel stayed at {before:?} after {after:?}, so window {:#x} was resized by one pixel and back, rect restored {restored}, panel now at {:?}",
window as usize,
frame_layout::panel_bounds(window).map(|panel| panel.x)
));
}

/// Shows or puts away the floating appbar of a hidden one, sliding it.
unsafe fn set_peek(window: HWND, on: bool) {
let changed = edit_layout(window, |layout| {
Expand Down Expand Up @@ -4710,6 +4771,43 @@ unsafe fn handle(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) ->
}
}

#[cfg(test)]
mod nudge_tests {
use super::*;

#[test]
fn fr2_a_fold_resizes_the_window_only_when_its_panel_did_not_move() {
let normal = NudgeState::default();
// The relayout moved the panel: nothing more.
assert!(!needs_size_nudge(Some(268), Some(8), normal));
// The panel stayed where it was: a size change lays it out.
assert!(needs_size_nudge(Some(268), Some(268), normal));
// No panel known yet: the window's own first layout comes.
assert!(!needs_size_nudge(None, None, normal));
// Never a window without a size of its own.
for state in [
NudgeState {
minimized: true,
..normal
},
NudgeState {
maximized: true,
..normal
},
NudgeState {
snapped: true,
..normal
},
NudgeState {
fullscreen: true,
..normal
},
] {
assert!(!needs_size_nudge(Some(268), Some(268), state));
}
}
}

#[cfg(test)]
mod laps_tests {
use super::*;
Expand Down
8 changes: 0 additions & 8 deletions rivet/runtime/windows/src/hooks/page_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,14 +279,6 @@ pub(crate) unsafe fn relayout(window: HWND) {
}) {
let layout: unsafe extern "system" fn(*mut c_void) =
std::mem::transmute(base + row().layout_immediately);
// The browser view sits in the client view, below the non-client view that gives the
// client view its bounds. That view is laid out first, so a new appbar width reaches the
// page even where the frame view's own layout is not recorded, as on Whale.
if let Some(non_client) = crate::chromium::view::parent_of(host)
.and_then(|client| crate::chromium::view::parent_of(client))
{
layout(non_client as *mut c_void);
}
layout(host as *mut c_void);
}
}
Expand Down
Loading