Remember window restore size (#10429)

Now, regardless of how the Zed window is closed, Zed can remember the
window's restore size.

- [x] Windows implementation
- [x] macOS implementation
- [x] Linux implementation (partial)
- [x] update SQL data base (mark column `fullscreen` as deprecated)

The current implementation on Linux is basic, and I'm not sure if it's
correct.

The variable `fullscreen` in SQL can be removed, but I'm unsure how to
do it.
edit: mark `fullscreen` as deprecated

### Case 1

When the window is closed as maximized, reopening it will open in the
maximized state, and returning from maximized state will restore the
position and size it had when it was maximized.



https://github.com/zed-industries/zed/assets/14981363/7207752e-878a-4d43-93a7-41ad1fdb3a06


### Case 2

When the window is closed as fullscreen, reopening it will open in
fullscreen mode, and toggling fullscreen will restore the position and
size it had when it entered fullscreen (note that the fullscreen
application was not recorded in the video, showing a black screen, but
it had actually entered fullscreen mode).



https://github.com/zed-industries/zed/assets/14981363/ea5aa70d-b296-462a-afb3-4c3372883ea3

### What's more

- As English is not my native language, some variable and struct names
may need to be modified to match their actual meaning.
- I am not familiar with the APIs related to macOS and Linux, so
implementation for these two platforms has not been done for now.
- Any suggestions and ideas are welcome.

Release Notes:

- N/A
This commit is contained in:
张小白 2024-05-08 13:29:03 +08:00 committed by GitHub
parent 6ddcff25e3
commit 63a5f46df4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 319 additions and 219 deletions

View file

@ -63,7 +63,11 @@ fn main() {
.with_assets(Assets {})
.run(|cx: &mut AppContext| {
let options = WindowOptions {
bounds: Some(Bounds::centered(None, size(px(300.), px(300.)), cx)),
window_bounds: Some(WindowBounds::Windowed(Bounds::centered(
None,
size(px(300.), px(300.)),
cx,
))),
..Default::default()
};
cx.open_window(options, |cx| {

View file

@ -26,7 +26,7 @@ fn main() {
let bounds = Bounds::centered(None, size(px(600.0), px(600.0)), cx);
cx.open_window(
WindowOptions {
bounds: Some(bounds),
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| {

View file

@ -79,10 +79,10 @@ fn main() {
..Default::default()
}),
bounds: Some(Bounds {
window_bounds: Some(WindowBounds::Windowed(Bounds {
size: size(px(1100.), px(600.)).into(),
origin: Point::new(DevicePixels::from(200), DevicePixels::from(200)),
}),
})),
..Default::default()
};

View file

@ -43,7 +43,7 @@ fn main() {
WindowOptions {
// Set the bounds of the window in screen coordinates
bounds: Some(bounds),
window_bounds: Some(WindowBounds::Windowed(bounds)),
// Specify the display_id to ensure the window is created on the correct screen
display_id: Some(screen.id()),
@ -53,7 +53,6 @@ fn main() {
show: true,
kind: WindowKind::PopUp,
is_movable: false,
fullscreen: false,
app_id: None,
}
};

View file

@ -4,8 +4,8 @@ use crate::{
Element, Empty, Entity, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Model,
ModelContext, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent,
MouseUpEvent, Pixels, Platform, Point, Render, Result, Size, Task, TestDispatcher,
TestPlatform, TestWindow, TextSystem, View, ViewContext, VisualContext, WindowContext,
WindowHandle, WindowOptions,
TestPlatform, TestWindow, TextSystem, View, ViewContext, VisualContext, WindowBounds,
WindowContext, WindowHandle, WindowOptions,
};
use anyhow::{anyhow, bail};
use futures::{channel::oneshot, Stream, StreamExt};
@ -188,7 +188,7 @@ impl TestAppContext {
let bounds = Bounds::maximized(None, &mut cx);
cx.open_window(
WindowOptions {
bounds: Some(bounds),
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| cx.new_view(build_window),
@ -201,7 +201,7 @@ impl TestAppContext {
let bounds = Bounds::maximized(None, &mut cx);
let window = cx.open_window(
WindowOptions {
bounds: Some(bounds),
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| cx.new_view(|_| Empty),
@ -224,7 +224,7 @@ impl TestAppContext {
let bounds = Bounds::maximized(None, &mut cx);
let window = cx.open_window(
WindowOptions {
bounds: Some(bounds),
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| cx.new_view(build_root_view),

View file

@ -184,7 +184,7 @@ unsafe impl Send for DisplayId {}
pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
fn bounds(&self) -> Bounds<DevicePixels>;
fn is_maximized(&self) -> bool;
fn is_minimized(&self) -> bool;
fn window_bounds(&self) -> WindowBounds;
fn content_size(&self) -> Size<Pixels>;
fn scale_factor(&self) -> f32;
fn appearance(&self) -> WindowAppearance;
@ -515,9 +515,10 @@ pub trait InputHandler: 'static {
/// The variables that can be configured when creating a new window
#[derive(Debug)]
pub struct WindowOptions {
/// The bounds of the window in screen coordinates.
/// None -> inherit, Some(bounds) -> set bounds
pub bounds: Option<Bounds<DevicePixels>>,
/// Specifies the state and bounds of the window in screen coordinates.
/// - `None`: Inherit the bounds.
/// - `Some(WindowBounds)`: Open a window with corresponding state and its restore size.
pub window_bounds: Option<WindowBounds>,
/// The titlebar configuration of the window
pub titlebar: Option<TitlebarOptions>,
@ -528,9 +529,6 @@ pub struct WindowOptions {
/// Whether the window should be shown when created
pub show: bool,
/// Whether the window should be fullscreen when created
pub fullscreen: bool,
/// The kind of window to create
pub kind: WindowKind,
@ -571,10 +569,40 @@ pub(crate) struct WindowParams {
pub window_background: WindowBackgroundAppearance,
}
/// Represents the status of how a window should be opened.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum WindowBounds {
/// Indicates that the window should open in a windowed state with the given bounds.
Windowed(Bounds<DevicePixels>),
/// Indicates that the window should open in a maximized state.
/// The bounds provided here represent the restore size of the window.
Maximized(Bounds<DevicePixels>),
/// Indicates that the window should open in fullscreen mode.
/// The bounds provided here represent the restore size of the window.
Fullscreen(Bounds<DevicePixels>),
}
impl Default for WindowBounds {
fn default() -> Self {
WindowBounds::Windowed(Bounds::default())
}
}
impl WindowBounds {
/// Retrieve the inner bounds
pub fn get_bounds(&self) -> Bounds<DevicePixels> {
match self {
WindowBounds::Windowed(bounds) => *bounds,
WindowBounds::Maximized(bounds) => *bounds,
WindowBounds::Fullscreen(bounds) => *bounds,
}
}
}
impl Default for WindowOptions {
fn default() -> Self {
Self {
bounds: None,
window_bounds: None,
titlebar: Some(TitlebarOptions {
title: Default::default(),
appears_transparent: Default::default(),
@ -585,7 +613,6 @@ impl Default for WindowOptions {
kind: WindowKind::Normal,
is_movable: true,
display_id: None,
fullscreen: false,
window_background: WindowBackgroundAppearance::default(),
app_id: None,
}

View file

@ -28,7 +28,7 @@ use crate::scene::Scene;
use crate::{
px, size, Bounds, DevicePixels, Globals, Modifiers, Pixels, PlatformDisplay, PlatformInput,
Point, PromptLevel, Size, WaylandClientState, WaylandClientStatePtr, WindowAppearance,
WindowBackgroundAppearance, WindowParams,
WindowBackgroundAppearance, WindowBounds, WindowParams,
};
#[derive(Default)]
@ -79,6 +79,7 @@ pub struct WaylandWindowState {
input_handler: Option<PlatformInputHandler>,
decoration_state: WaylandDecorationState,
fullscreen: bool,
restore_bounds: Bounds<DevicePixels>,
maximized: bool,
client: WaylandClientStatePtr,
callbacks: Callbacks,
@ -151,6 +152,7 @@ impl WaylandWindowState {
input_handler: None,
decoration_state: WaylandDecorationState::Client,
fullscreen: false,
restore_bounds: Bounds::default(),
maximized: false,
callbacks: Callbacks::default(),
client,
@ -332,10 +334,15 @@ impl WaylandWindowStatePtr {
let height = NonZeroU32::new(height as u32);
let fullscreen = states.contains(&(xdg_toplevel::State::Fullscreen as u8));
let maximized = states.contains(&(xdg_toplevel::State::Maximized as u8));
self.resize(width, height);
self.set_fullscreen(fullscreen);
let mut state = self.state.borrow_mut();
state.maximized = maximized;
state.fullscreen = fullscreen;
if fullscreen || maximized {
state.restore_bounds = state.bounds.map(|p| DevicePixels(p as i32));
}
drop(state);
self.resize(width, height);
self.set_fullscreen(fullscreen);
false
}
@ -545,9 +552,17 @@ impl PlatformWindow for WaylandWindow {
self.borrow().maximized
}
fn is_minimized(&self) -> bool {
// This cannot be determined by the client
false
// todo(linux)
// check if it is right
fn window_bounds(&self) -> WindowBounds {
let state = self.borrow();
if state.fullscreen {
WindowBounds::Fullscreen(state.restore_bounds)
} else if state.maximized {
WindowBounds::Maximized(state.restore_bounds)
} else {
WindowBounds::Windowed(state.bounds.map(|p| DevicePixels(p as i32)))
}
}
fn content_size(&self) -> Size<Pixels> {
@ -679,7 +694,8 @@ impl PlatformWindow for WaylandWindow {
}
fn toggle_fullscreen(&self) {
let state = self.borrow();
let mut state = self.borrow_mut();
state.restore_bounds = state.bounds.map(|p| DevicePixels(p as i32));
if !state.fullscreen {
state.toplevel.set_fullscreen(None);
} else {

View file

@ -5,8 +5,8 @@ use crate::{
platform::blade::{BladeRenderer, BladeSurfaceConfig},
size, Bounds, DevicePixels, ForegroundExecutor, Modifiers, Pixels, Platform, PlatformAtlas,
PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PromptLevel,
Scene, Size, WindowAppearance, WindowBackgroundAppearance, WindowOptions, WindowParams,
X11Client, X11ClientState, X11ClientStatePtr,
Scene, Size, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowOptions,
WindowParams, X11Client, X11ClientState, X11ClientStatePtr,
};
use blade_graphics as gpu;
use parking_lot::Mutex;
@ -526,8 +526,9 @@ impl PlatformWindow for X11Window {
}
// todo(linux)
fn is_minimized(&self) -> bool {
false
fn window_bounds(&self) -> WindowBounds {
let state = self.0.state.borrow();
WindowBounds::Windowed(state.bounds.map(|p| DevicePixels(p)))
}
fn content_size(&self) -> Size<Pixels> {

View file

@ -4,7 +4,8 @@ use crate::{
DisplayLink, ExternalPaths, FileDropEvent, ForegroundExecutor, KeyDownEvent, Keystroke,
Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptLevel,
Size, Timer, WindowAppearance, WindowBackgroundAppearance, WindowKind, WindowParams,
Size, Timer, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowKind,
WindowParams,
};
use block::ConcreteBlock;
use cocoa::{
@ -259,6 +260,10 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C
sel!(windowDidChangeOcclusionState:),
window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowWillEnterFullScreen:),
window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidMove:),
window_did_move as extern "C" fn(&Object, Sel, id),
@ -302,14 +307,6 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C
sel!(concludeDragOperation:),
conclude_drag_operation as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidMiniaturize:),
window_did_miniaturize as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidDeminiaturize:),
window_did_deminiaturize as extern "C" fn(&Object, Sel, id),
);
decl.register()
}
@ -348,7 +345,7 @@ struct MacWindowState {
external_files_dragged: bool,
// Whether the next left-mouse click is also the focusing click.
first_mouse: bool,
minimized: bool,
fullscreen_restore_bounds: Bounds<DevicePixels>,
}
impl MacWindowState {
@ -435,10 +432,6 @@ impl MacWindowState {
}
}
fn is_minimized(&self) -> bool {
self.minimized
}
fn is_fullscreen(&self) -> bool {
unsafe {
let style_mask = self.native_window.styleMask();
@ -494,6 +487,14 @@ impl MacWindowState {
px((frame.size.height - content_layout_rect.size.height) as f32)
}
}
fn window_bounds(&self) -> WindowBounds {
if self.is_fullscreen() {
WindowBounds::Fullscreen(self.fullscreen_restore_bounds)
} else {
WindowBounds::Windowed(self.bounds())
}
}
}
unsafe impl Send for MacWindowState {}
@ -639,7 +640,7 @@ impl MacWindow {
previous_keydown_inserted_text: None,
external_files_dragged: false,
first_mouse: false,
minimized: false,
fullscreen_restore_bounds: Bounds::default(),
})));
(*native_window).set_ivar(
@ -775,12 +776,12 @@ impl PlatformWindow for MacWindow {
self.0.as_ref().lock().bounds()
}
fn is_maximized(&self) -> bool {
self.0.as_ref().lock().is_maximized()
fn window_bounds(&self) -> WindowBounds {
self.0.as_ref().lock().window_bounds()
}
fn is_minimized(&self) -> bool {
self.0.as_ref().lock().is_minimized()
fn is_maximized(&self) -> bool {
self.0.as_ref().lock().is_maximized()
}
fn content_size(&self) -> Size<Pixels> {
@ -1466,6 +1467,12 @@ extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
window_state.as_ref().lock().move_traffic_light();
}
extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
let window_state = unsafe { get_window_state(this) };
let mut lock = window_state.as_ref().lock();
lock.fullscreen_restore_bounds = lock.bounds();
}
extern "C" fn window_did_move(this: &Object, _: Sel, _: id) {
let window_state = unsafe { get_window_state(this) };
let mut lock = window_state.as_ref().lock();
@ -1863,18 +1870,6 @@ extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: id) {
);
}
extern "C" fn window_did_miniaturize(this: &Object, _: Sel, _: id) {
let window_state = unsafe { get_window_state(this) };
window_state.lock().minimized = true;
}
extern "C" fn window_did_deminiaturize(this: &Object, _: Sel, _: id) {
let window_state = unsafe { get_window_state(this) };
window_state.lock().minimized = false;
}
async fn synthetic_drag(
window_state: Weak<Mutex<MacWindowState>>,
drag_id: usize,

View file

@ -2,7 +2,7 @@ use crate::{
AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DevicePixels,
DispatchEventResult, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
PlatformInputHandler, PlatformWindow, Point, Size, TestPlatform, TileId, WindowAppearance,
WindowBackgroundAppearance, WindowParams,
WindowBackgroundAppearance, WindowBounds, WindowParams,
};
use collections::HashMap;
use parking_lot::Mutex;
@ -112,11 +112,11 @@ impl PlatformWindow for TestWindow {
self.0.lock().bounds
}
fn is_maximized(&self) -> bool {
false
fn window_bounds(&self) -> WindowBounds {
WindowBounds::Windowed(self.bounds())
}
fn is_minimized(&self) -> bool {
fn is_maximized(&self) -> bool {
false
}

View file

@ -35,6 +35,7 @@ pub(crate) struct WindowsWindow(pub Rc<WindowsWindowStatePtr>);
pub struct WindowsWindowState {
pub origin: Point<DevicePixels>,
pub physical_size: Size<DevicePixels>,
pub fullscreen_restore_bounds: Bounds<DevicePixels>,
pub scale_factor: f32,
pub callbacks: Callbacks,
@ -71,6 +72,10 @@ impl WindowsWindowState {
) -> Self {
let origin = point(cs.x.into(), cs.y.into());
let physical_size = size(cs.cx.into(), cs.cy.into());
let fullscreen_restore_bounds = Bounds {
origin,
size: physical_size,
};
let scale_factor = {
let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32
@ -84,6 +89,7 @@ impl WindowsWindowState {
Self {
origin,
physical_size,
fullscreen_restore_bounds,
scale_factor,
callbacks,
input_handler,
@ -113,6 +119,35 @@ impl WindowsWindowState {
}
}
fn window_bounds(&self) -> WindowBounds {
let placement = unsafe {
let mut placement = WINDOWPLACEMENT {
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
..Default::default()
};
GetWindowPlacement(self.hwnd, &mut placement).log_err();
placement
};
let bounds = Bounds {
origin: point(
DevicePixels(placement.rcNormalPosition.left),
DevicePixels(placement.rcNormalPosition.top),
),
size: size(
DevicePixels(placement.rcNormalPosition.right - placement.rcNormalPosition.left),
DevicePixels(placement.rcNormalPosition.bottom - placement.rcNormalPosition.top),
),
};
if self.is_fullscreen() {
WindowBounds::Fullscreen(self.fullscreen_restore_bounds)
} else if placement.showCmd == SW_SHOWMAXIMIZED.0 as u32 {
WindowBounds::Maximized(bounds)
} else {
WindowBounds::Windowed(bounds)
}
}
/// get the logical size of the app's drawable area.
///
/// Currently, GPUI uses logical size of the app to handle mouse interactions (such as
@ -176,10 +211,6 @@ impl WindowsWindowStatePtr {
main_receiver: context.main_receiver.clone(),
})
}
fn is_minimized(&self) -> bool {
unsafe { IsIconic(self.hwnd) }.as_bool()
}
}
#[derive(Default)]
@ -209,7 +240,7 @@ struct WindowCreateContext {
impl WindowsWindow {
pub(crate) fn new(
handle: AnyWindowHandle,
options: WindowParams,
params: WindowParams,
icon: HICON,
executor: ForegroundExecutor,
main_receiver: flume::Receiver<Runnable>,
@ -217,13 +248,13 @@ impl WindowsWindow {
current_cursor: HCURSOR,
) -> Self {
let classname = register_wnd_class(icon);
let hide_title_bar = options
let hide_title_bar = params
.titlebar
.as_ref()
.map(|titlebar| titlebar.appears_transparent)
.unwrap_or(false);
let windowname = HSTRING::from(
options
params
.titlebar
.as_ref()
.and_then(|titlebar| titlebar.title.as_ref())
@ -231,12 +262,6 @@ impl WindowsWindow {
.unwrap_or(""),
);
let dwstyle = WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX;
let x = options.bounds.origin.x.0;
let y = options.bounds.origin.y.0;
let nwidth = options.bounds.size.width.0;
let nheight = options.bounds.size.height.0;
let hwndparent = HWND::default();
let hmenu = HMENU::default();
let hinstance = get_module_handle();
let mut context = WindowCreateContext {
inner: None,
@ -245,7 +270,7 @@ impl WindowsWindow {
// todo(windows) move window to target monitor
// options.display_id
display: WindowsDisplay::primary_monitor().unwrap(),
transparent: options.window_background != WindowBackgroundAppearance::Opaque,
transparent: params.window_background != WindowBackgroundAppearance::Opaque,
executor,
main_receiver,
mouse_wheel_settings,
@ -258,12 +283,12 @@ impl WindowsWindow {
classname,
&windowname,
dwstyle,
x,
y,
nwidth,
nheight,
hwndparent,
hmenu,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None,
None,
hinstance,
lpparam,
)
@ -272,6 +297,18 @@ impl WindowsWindow {
register_drag_drop(state_ptr.clone());
let wnd = Self(state_ptr);
unsafe {
let mut placement = WINDOWPLACEMENT {
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
..Default::default()
};
GetWindowPlacement(raw_hwnd, &mut placement).log_err();
placement.rcNormalPosition.left = params.bounds.left().0;
placement.rcNormalPosition.right = params.bounds.right().0;
placement.rcNormalPosition.top = params.bounds.top().0;
placement.rcNormalPosition.bottom = params.bounds.bottom().0;
SetWindowPlacement(raw_hwnd, &placement).log_err();
}
unsafe { ShowWindow(raw_hwnd, SW_SHOW) };
wnd
@ -321,8 +358,8 @@ impl PlatformWindow for WindowsWindow {
self.0.state.borrow().is_maximized()
}
fn is_minimized(&self) -> bool {
self.0.is_minimized()
fn window_bounds(&self) -> WindowBounds {
self.0.state.borrow().window_bounds()
}
/// get the logical size of the app's drawable area.
@ -493,6 +530,10 @@ impl PlatformWindow for WindowsWindow {
.executor
.spawn(async move {
let mut lock = state_ptr.state.borrow_mut();
lock.fullscreen_restore_bounds = Bounds {
origin: lock.origin,
size: lock.physical_size,
};
let StyleAndBounds {
style,
x,

View file

@ -12,8 +12,8 @@ use crate::{
RenderSvgParams, ScaledPixels, Scene, Shadow, SharedString, Size, StrikethroughStyle, Style,
SubscriberSet, Subscription, TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement,
TransformationMatrix, Underline, UnderlineStyle, View, VisualContext, WeakView,
WindowAppearance, WindowBackgroundAppearance, WindowOptions, WindowParams, WindowTextSystem,
SUBPIXEL_VARIANTS,
WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowOptions, WindowParams,
WindowTextSystem, SUBPIXEL_VARIANTS,
};
use anyhow::{anyhow, Context as _, Result};
use collections::{FxHashMap, FxHashSet};
@ -565,7 +565,7 @@ fn default_bounds(display_id: Option<DisplayId>, cx: &mut AppContext) -> Bounds<
const DEFAULT_WINDOW_OFFSET: Point<DevicePixels> = point(DevicePixels(0), DevicePixels(35));
cx.active_window()
.and_then(|w| w.update(cx, |_, cx| cx.window_bounds()).ok())
.and_then(|w| w.update(cx, |_, cx| cx.bounds()).ok())
.map(|bounds| bounds.map_origin(|origin| origin + DEFAULT_WINDOW_OFFSET))
.unwrap_or_else(|| {
let display = display_id
@ -592,19 +592,20 @@ impl Window {
cx: &mut AppContext,
) -> Self {
let WindowOptions {
bounds,
window_bounds,
titlebar,
focus,
show,
kind,
is_movable,
display_id,
fullscreen,
window_background,
app_id,
} = options;
let bounds = bounds.unwrap_or_else(|| default_bounds(display_id, cx));
let bounds = window_bounds
.map(|bounds| bounds.get_bounds())
.unwrap_or_else(|| default_bounds(display_id, cx));
let mut platform_window = cx.platform.open_window(
handle,
WindowParams {
@ -632,8 +633,12 @@ impl Window {
let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
let last_input_timestamp = Rc::new(Cell::new(Instant::now()));
if fullscreen {
platform_window.toggle_fullscreen();
if let Some(ref window_open_state) = window_bounds {
match window_open_state {
WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
WindowBounds::Maximized(_) => platform_window.zoom(),
WindowBounds::Windowed(_) => {}
}
}
platform_window.on_close(Box::new({
@ -691,7 +696,7 @@ impl Window {
let mut cx = cx.to_async();
move |_, _| {
handle
.update(&mut cx, |_, cx| cx.window_bounds_changed())
.update(&mut cx, |_, cx| cx.bounds_changed())
.log_err();
}
}));
@ -699,7 +704,7 @@ impl Window {
let mut cx = cx.to_async();
move || {
handle
.update(&mut cx, |_, cx| cx.window_bounds_changed())
.update(&mut cx, |_, cx| cx.bounds_changed())
.log_err();
}
}));
@ -943,10 +948,10 @@ impl<'a> WindowContext<'a> {
self.window.platform_window.is_maximized()
}
/// Check if the platform window is minimized
/// On some platforms (namely Windows) the position is incorrect when minimized
pub fn is_minimized(&self) -> bool {
self.window.platform_window.is_minimized()
/// Return the `WindowBounds` to indicate that how a window should be opened
/// after it has been closed
pub fn window_bounds(&self) -> WindowBounds {
self.window.platform_window.window_bounds()
}
/// Dispatch the given action on the currently focused element.
@ -1075,7 +1080,7 @@ impl<'a> WindowContext<'a> {
.spawn(|app| f(AsyncWindowContext::new(app, self.window.handle)))
}
fn window_bounds_changed(&mut self) {
fn bounds_changed(&mut self) {
self.window.scale_factor = self.window.platform_window.scale_factor();
self.window.viewport_size = self.window.platform_window.content_size();
self.window.display_id = self.window.platform_window.display().id();
@ -1088,7 +1093,7 @@ impl<'a> WindowContext<'a> {
}
/// Returns the bounds of the current window in the global coordinate space, which could span across multiple displays.
pub fn window_bounds(&self) -> Bounds<DevicePixels> {
pub fn bounds(&self) -> Bounds<DevicePixels> {
self.window.platform_window.bounds()
}