Compare commits
100 Commits
github-tok
...
restore-ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f3f5c6ebd | ||
|
|
e9df71b124 | ||
|
|
23997f3331 | ||
|
|
ca6285bbe6 | ||
|
|
4d19d22b3f | ||
|
|
f1c097568f | ||
|
|
2b00564518 | ||
|
|
33da303148 | ||
|
|
4d656dba84 | ||
|
|
ca5dfaed8c | ||
|
|
74cb91ee7d | ||
|
|
22b1760486 | ||
|
|
3560bf7e51 | ||
|
|
38f889ac97 | ||
|
|
9a1bbb2dd3 | ||
|
|
7debce8b4b | ||
|
|
8d8490b79a | ||
|
|
afe58e42ba | ||
|
|
fadbf4690a | ||
|
|
eb9da1888b | ||
|
|
e7bc90ef91 | ||
|
|
a06ce20503 | ||
|
|
5b6899a226 | ||
|
|
b5ae7bc893 | ||
|
|
8b4273ee5e | ||
|
|
9eeb45d67b | ||
|
|
04e8a44c23 | ||
|
|
cfbbaeab50 | ||
|
|
1486fe0a59 | ||
|
|
af26d6bbcf | ||
|
|
882ced6949 | ||
|
|
f39e977363 | ||
|
|
107dd9081d | ||
|
|
7502b46c1f | ||
|
|
ee9579a84f | ||
|
|
b9818c6984 | ||
|
|
7f7755af68 | ||
|
|
5bfb26510f | ||
|
|
a32346db25 | ||
|
|
8d0d02b887 | ||
|
|
06f3f52159 | ||
|
|
2a3048aca7 | ||
|
|
f2cf9fefe7 | ||
|
|
dab7b8220b | ||
|
|
1e9fd8364d | ||
|
|
ae1428679a | ||
|
|
80628911b2 | ||
|
|
040babebf9 | ||
|
|
9032a8b111 | ||
|
|
b9228f1dc1 | ||
|
|
d4b7e88aeb | ||
|
|
7275d61f82 | ||
|
|
451cd47a7e | ||
|
|
68d1ccfeb1 | ||
|
|
0c17f691c0 | ||
|
|
d130d3e02e | ||
|
|
d541a75e3c | ||
|
|
1ccad5b078 | ||
|
|
696d496367 | ||
|
|
20d9a3e8db | ||
|
|
691a2e983d | ||
|
|
2c5a7ddd00 | ||
|
|
2b2d5ea813 | ||
|
|
8b8ef5fbe4 | ||
|
|
03c60f943e | ||
|
|
48f875f9d8 | ||
|
|
b0d43e51bb | ||
|
|
92481a93aa | ||
|
|
300121f5cc | ||
|
|
056adae16c | ||
|
|
24e07874b3 | ||
|
|
fbd87c96d0 | ||
|
|
dabce12916 | ||
|
|
84369f3e4b | ||
|
|
d54ba0e579 | ||
|
|
7fca2173ce | ||
|
|
8034b76867 | ||
|
|
de38629efb | ||
|
|
7a4f6677cc | ||
|
|
0cd31c8da3 | ||
|
|
2410470d72 | ||
|
|
ab6ff3ffcc | ||
|
|
f261cf513a | ||
|
|
b1c01ef45c | ||
|
|
8616381ed9 | ||
|
|
66d702922e | ||
|
|
0386f76e55 | ||
|
|
ae8f9ad22f | ||
|
|
608469eca8 | ||
|
|
9fe0184cad | ||
|
|
4669b14c57 | ||
|
|
40fe820aae | ||
|
|
ea086316ed | ||
|
|
c62970a6cc | ||
|
|
218a7e2b69 | ||
|
|
a8b9393477 | ||
|
|
6c4d5bcbd5 | ||
|
|
e72b94bbbf | ||
|
|
49e085037e | ||
|
|
7c0ea926f0 |
@@ -14,7 +14,7 @@ pub use collab_panel::CollabPanel;
|
||||
pub use collab_titlebar_item::CollabTitlebarItem;
|
||||
use gpui::{
|
||||
actions, point, AppContext, DevicePixels, Pixels, PlatformDisplay, Size, Task,
|
||||
WindowBackgroundAppearance, WindowContext, WindowKind, WindowOptions,
|
||||
WindowBackgroundAppearance, WindowBounds, WindowContext, WindowKind, WindowOptions,
|
||||
};
|
||||
use panel_settings::MessageEditorSettings;
|
||||
pub use panel_settings::{
|
||||
@@ -117,14 +117,13 @@ fn notification_window_options(
|
||||
let app_id = ReleaseChannel::global(cx).app_id();
|
||||
|
||||
WindowOptions {
|
||||
bounds: Some(bounds),
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||
titlebar: None,
|
||||
focus: false,
|
||||
show: true,
|
||||
kind: WindowKind::PopUp,
|
||||
is_movable: false,
|
||||
display_id: Some(screen.id()),
|
||||
fullscreen: false,
|
||||
window_background: WindowBackgroundAppearance::default(),
|
||||
app_id: Some(app_id.to_owned()),
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
JoinLines,
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use gpui::{div, TestAppContext, VisualTestContext, WindowOptions};
|
||||
use gpui::{div, TestAppContext, VisualTestContext, WindowBounds, WindowOptions};
|
||||
use indoc::indoc;
|
||||
use language::{
|
||||
language_settings::{AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent},
|
||||
@@ -7468,10 +7468,10 @@ async fn test_following(cx: &mut gpui::TestAppContext) {
|
||||
let follower = cx.update(|cx| {
|
||||
cx.open_window(
|
||||
WindowOptions {
|
||||
bounds: Some(Bounds::from_corners(
|
||||
window_bounds: Some(WindowBounds::Windowed(Bounds::from_corners(
|
||||
gpui::Point::new(0.into(), 0.into()),
|
||||
gpui::Point::new(10.into(), 80.into()),
|
||||
)),
|
||||
))),
|
||||
..Default::default()
|
||||
},
|
||||
|cx| cx.new_view(|cx| build_editor(buffer.clone(), cx)),
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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::{
|
||||
@@ -302,14 +303,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 +341,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 +428,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 +483,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 +636,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 +772,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> {
|
||||
@@ -1863,18 +1860,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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ pub(crate) struct WindowsWindowInner {
|
||||
hwnd: HWND,
|
||||
origin: Cell<Point<DevicePixels>>,
|
||||
physical_size: Cell<Size<DevicePixels>>,
|
||||
fullscreen_restore_bounds: Cell<Bounds<DevicePixels>>,
|
||||
scale_factor: Cell<f32>,
|
||||
input_handler: Cell<Option<PlatformInputHandler>>,
|
||||
renderer: RefCell<BladeRenderer>,
|
||||
@@ -65,14 +66,8 @@ impl WindowsWindowInner {
|
||||
transparent: bool,
|
||||
) -> Self {
|
||||
let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
|
||||
let origin = Cell::new(Point {
|
||||
x: DevicePixels(cs.x),
|
||||
y: DevicePixels(cs.y),
|
||||
});
|
||||
let physical_size = Cell::new(Size {
|
||||
width: DevicePixels(cs.cx),
|
||||
height: DevicePixels(cs.cy),
|
||||
});
|
||||
let origin = Cell::new(point(DevicePixels(cs.x), DevicePixels(cs.y)));
|
||||
let physical_size = Cell::new(size(DevicePixels(cs.cx), DevicePixels(cs.cy)));
|
||||
let scale_factor = Cell::new(monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32);
|
||||
let input_handler = Cell::new(None);
|
||||
struct RawWindow {
|
||||
@@ -119,10 +114,13 @@ impl WindowsWindowInner {
|
||||
let display = RefCell::new(display);
|
||||
let click_state = RefCell::new(ClickState::new());
|
||||
let fullscreen = Cell::new(None);
|
||||
let fullscreen_restore_bounds = Cell::new(Bounds::default());
|
||||
|
||||
Self {
|
||||
hwnd,
|
||||
origin,
|
||||
physical_size,
|
||||
fullscreen_restore_bounds,
|
||||
scale_factor,
|
||||
input_handler,
|
||||
renderer,
|
||||
@@ -140,8 +138,33 @@ impl WindowsWindowInner {
|
||||
!self.is_fullscreen() && unsafe { IsZoomed(self.hwnd) }.as_bool()
|
||||
}
|
||||
|
||||
fn is_minimized(&self) -> bool {
|
||||
unsafe { IsIconic(self.hwnd) }.as_bool()
|
||||
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.get())
|
||||
} else if placement.showCmd == SW_SHOWMAXIMIZED.0 as u32 {
|
||||
WindowBounds::Maximized(bounds)
|
||||
} else {
|
||||
WindowBounds::Windowed(bounds)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fullscreen(&self) -> bool {
|
||||
@@ -152,6 +175,10 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
async fn toggle_fullscreen(self: Rc<Self>) {
|
||||
self.fullscreen_restore_bounds.set(Bounds {
|
||||
origin: self.origin.get(),
|
||||
size: self.physical_size.get(),
|
||||
});
|
||||
let StyleAndBounds {
|
||||
style,
|
||||
x,
|
||||
@@ -304,10 +331,7 @@ impl WindowsWindowInner {
|
||||
fn handle_move_msg(&self, lparam: LPARAM) -> Option<isize> {
|
||||
let x = lparam.signed_loword() as i32;
|
||||
let y = lparam.signed_hiword() as i32;
|
||||
self.origin.set(Point {
|
||||
x: DevicePixels(x),
|
||||
y: DevicePixels(y),
|
||||
});
|
||||
self.origin.set(point(DevicePixels(x), DevicePixels(y)));
|
||||
let size = self.physical_size.get();
|
||||
let center_x = x + size.width.0 / 2;
|
||||
let center_y = y + size.height.0 / 2;
|
||||
@@ -1246,16 +1270,16 @@ impl WindowsWindow {
|
||||
pub(crate) fn new(
|
||||
platform_inner: Rc<WindowsPlatformInner>,
|
||||
handle: AnyWindowHandle,
|
||||
options: WindowParams,
|
||||
params: WindowParams,
|
||||
) -> Self {
|
||||
let classname = register_wnd_class(platform_inner.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())
|
||||
@@ -1263,12 +1287,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,
|
||||
@@ -1287,12 +1305,12 @@ impl WindowsWindow {
|
||||
classname,
|
||||
&windowname,
|
||||
dwstyle,
|
||||
x,
|
||||
y,
|
||||
nwidth,
|
||||
nheight,
|
||||
hwndparent,
|
||||
hmenu,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
None,
|
||||
None,
|
||||
hinstance,
|
||||
lpparam,
|
||||
)
|
||||
@@ -1316,7 +1334,20 @@ impl WindowsWindow {
|
||||
.write()
|
||||
.push(wnd.inner.hwnd);
|
||||
|
||||
unsafe {
|
||||
let mut placement = WINDOWPLACEMENT {
|
||||
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
GetWindowPlacement(wnd.inner.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(wnd.inner.hwnd, &placement).log_err();
|
||||
}
|
||||
unsafe { ShowWindow(wnd.inner.hwnd, SW_SHOW) };
|
||||
|
||||
wnd
|
||||
}
|
||||
}
|
||||
@@ -1358,8 +1389,8 @@ impl PlatformWindow for WindowsWindow {
|
||||
self.inner.is_maximized()
|
||||
}
|
||||
|
||||
fn is_minimized(&self) -> bool {
|
||||
self.inner.is_minimized()
|
||||
fn window_bounds(&self) -> WindowBounds {
|
||||
self.inner.window_bounds()
|
||||
}
|
||||
|
||||
/// get the logical size of the app's drawable area.
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ mod story_selector;
|
||||
use clap::Parser;
|
||||
use dialoguer::FuzzySelect;
|
||||
use gpui::{
|
||||
div, px, size, AnyView, AppContext, Bounds, Render, ViewContext, VisualContext, WindowOptions,
|
||||
div, px, size, AnyView, AppContext, Bounds, Render, ViewContext, VisualContext, WindowBounds,
|
||||
WindowOptions,
|
||||
};
|
||||
use log::LevelFilter;
|
||||
use project::Project;
|
||||
@@ -85,7 +86,7 @@ fn main() {
|
||||
let bounds = Bounds::centered(None, size, cx);
|
||||
let _window = cx.open_window(
|
||||
WindowOptions {
|
||||
bounds: Some(bounds),
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||
..Default::default()
|
||||
},
|
||||
move |cx| {
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::path::Path;
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use client::DevServerProjectId;
|
||||
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
|
||||
use gpui::{point, size, Axis, Bounds};
|
||||
use gpui::{point, size, Axis, Bounds, WindowBounds};
|
||||
|
||||
use sqlez::{
|
||||
bindable::{Bind, Column, StaticColumnCount},
|
||||
@@ -59,50 +59,99 @@ impl sqlez::bindable::Column for SerializedAxis {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) struct SerializedWindowsBounds(pub(crate) Bounds<gpui::DevicePixels>);
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
||||
pub(crate) struct SerializedWindowBounds(pub(crate) WindowBounds);
|
||||
|
||||
impl StaticColumnCount for SerializedWindowsBounds {
|
||||
impl StaticColumnCount for SerializedWindowBounds {
|
||||
fn column_count() -> usize {
|
||||
5
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind for SerializedWindowsBounds {
|
||||
impl Bind for SerializedWindowBounds {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
let next_index = statement.bind(&"Fixed", start_index)?;
|
||||
|
||||
statement.bind(
|
||||
&(
|
||||
SerializedDevicePixels(self.0.origin.x),
|
||||
SerializedDevicePixels(self.0.origin.y),
|
||||
SerializedDevicePixels(self.0.size.width),
|
||||
SerializedDevicePixels(self.0.size.height),
|
||||
),
|
||||
next_index,
|
||||
)
|
||||
match self.0 {
|
||||
WindowBounds::Windowed(bounds) => {
|
||||
let next_index = statement.bind(&"Windowed", start_index)?;
|
||||
statement.bind(
|
||||
&(
|
||||
SerializedDevicePixels(bounds.origin.x),
|
||||
SerializedDevicePixels(bounds.origin.y),
|
||||
SerializedDevicePixels(bounds.size.width),
|
||||
SerializedDevicePixels(bounds.size.height),
|
||||
),
|
||||
next_index,
|
||||
)
|
||||
}
|
||||
WindowBounds::Maximized(bounds) => {
|
||||
let next_index = statement.bind(&"Maximized", start_index)?;
|
||||
statement.bind(
|
||||
&(
|
||||
SerializedDevicePixels(bounds.origin.x),
|
||||
SerializedDevicePixels(bounds.origin.y),
|
||||
SerializedDevicePixels(bounds.size.width),
|
||||
SerializedDevicePixels(bounds.size.height),
|
||||
),
|
||||
next_index,
|
||||
)
|
||||
}
|
||||
WindowBounds::Fullscreen(bounds) => {
|
||||
let next_index = statement.bind(&"FullScreen", start_index)?;
|
||||
statement.bind(
|
||||
&(
|
||||
SerializedDevicePixels(bounds.origin.x),
|
||||
SerializedDevicePixels(bounds.origin.y),
|
||||
SerializedDevicePixels(bounds.size.width),
|
||||
SerializedDevicePixels(bounds.size.height),
|
||||
),
|
||||
next_index,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Column for SerializedWindowsBounds {
|
||||
impl Column for SerializedWindowBounds {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let (window_state, next_index) = String::column(statement, start_index)?;
|
||||
let bounds = match window_state.as_str() {
|
||||
"Fixed" => {
|
||||
let status = match window_state.as_str() {
|
||||
"Windowed" | "Fixed" => {
|
||||
let ((x, y, width, height), _) = Column::column(statement, next_index)?;
|
||||
let x: i32 = x;
|
||||
let y: i32 = y;
|
||||
let width: i32 = width;
|
||||
let height: i32 = height;
|
||||
SerializedWindowsBounds(Bounds {
|
||||
SerializedWindowBounds(WindowBounds::Windowed(Bounds {
|
||||
origin: point(x.into(), y.into()),
|
||||
size: size(width.into(), height.into()),
|
||||
})
|
||||
}))
|
||||
}
|
||||
"Maximized" => {
|
||||
let ((x, y, width, height), _) = Column::column(statement, next_index)?;
|
||||
let x: i32 = x;
|
||||
let y: i32 = y;
|
||||
let width: i32 = width;
|
||||
let height: i32 = height;
|
||||
SerializedWindowBounds(WindowBounds::Maximized(Bounds {
|
||||
origin: point(x.into(), y.into()),
|
||||
size: size(width.into(), height.into()),
|
||||
}))
|
||||
}
|
||||
"FullScreen" => {
|
||||
let ((x, y, width, height), _) = Column::column(statement, next_index)?;
|
||||
let x: i32 = x;
|
||||
let y: i32 = y;
|
||||
let width: i32 = width;
|
||||
let height: i32 = height;
|
||||
SerializedWindowBounds(WindowBounds::Fullscreen(Bounds {
|
||||
origin: point(x.into(), y.into()),
|
||||
size: size(width.into(), height.into()),
|
||||
}))
|
||||
}
|
||||
_ => bail!("Window State did not have a valid string"),
|
||||
};
|
||||
|
||||
Ok((bounds, next_index + 4))
|
||||
Ok((status, next_index + 4))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +328,8 @@ define_connection! {
|
||||
ALTER TABLE pane_groups ADD COLUMN flexes TEXT;
|
||||
),
|
||||
// Add fullscreen field to workspace
|
||||
// Deprecated, `WindowBounds` holds the fullscreen state now.
|
||||
// Preserving so users can downgrade Zed.
|
||||
sql!(
|
||||
ALTER TABLE workspaces ADD COLUMN fullscreen INTEGER; //bool
|
||||
),
|
||||
@@ -328,19 +379,17 @@ impl WorkspaceDb {
|
||||
workspace_id,
|
||||
local_paths,
|
||||
dev_server_project_id,
|
||||
bounds,
|
||||
window_bounds,
|
||||
display,
|
||||
fullscreen,
|
||||
centered_layout,
|
||||
docks,
|
||||
): (
|
||||
WorkspaceId,
|
||||
Option<LocalPaths>,
|
||||
Option<u64>,
|
||||
Option<SerializedWindowsBounds>,
|
||||
Option<SerializedWindowBounds>,
|
||||
Option<Uuid>,
|
||||
Option<bool>,
|
||||
Option<bool>,
|
||||
DockStructure,
|
||||
) = self
|
||||
.select_row_bound(sql! {
|
||||
@@ -354,7 +403,6 @@ impl WorkspaceDb {
|
||||
window_width,
|
||||
window_height,
|
||||
display,
|
||||
fullscreen,
|
||||
centered_layout,
|
||||
left_dock_visible,
|
||||
left_dock_active_panel,
|
||||
@@ -398,8 +446,7 @@ impl WorkspaceDb {
|
||||
.get_center_pane_group(workspace_id)
|
||||
.context("Getting center group")
|
||||
.log_err()?,
|
||||
bounds: bounds.map(|bounds| bounds.0),
|
||||
fullscreen: fullscreen.unwrap_or(false),
|
||||
window_bounds,
|
||||
centered_layout: centered_layout.unwrap_or(false),
|
||||
display,
|
||||
docks,
|
||||
@@ -549,13 +596,12 @@ impl WorkspaceDb {
|
||||
|
||||
pub(crate) fn last_window(
|
||||
&self,
|
||||
) -> anyhow::Result<(Option<Uuid>, Option<SerializedWindowsBounds>, Option<bool>)> {
|
||||
) -> anyhow::Result<(Option<Uuid>, Option<SerializedWindowBounds>)> {
|
||||
let mut prepared_query =
|
||||
self.select::<(Option<Uuid>, Option<SerializedWindowsBounds>, Option<bool>)>(sql!(
|
||||
self.select::<(Option<Uuid>, Option<SerializedWindowBounds>)>(sql!(
|
||||
SELECT
|
||||
display,
|
||||
window_state, window_x, window_y, window_width, window_height,
|
||||
fullscreen
|
||||
window_state, window_x, window_y, window_width, window_height
|
||||
FROM workspaces
|
||||
WHERE local_paths
|
||||
IS NOT NULL
|
||||
@@ -563,10 +609,7 @@ impl WorkspaceDb {
|
||||
LIMIT 1
|
||||
))?;
|
||||
let result = prepared_query()?;
|
||||
Ok(result
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap_or_else(|| (None, None, None)))
|
||||
Ok(result.into_iter().next().unwrap_or_else(|| (None, None)))
|
||||
}
|
||||
|
||||
query! {
|
||||
@@ -829,7 +872,7 @@ impl WorkspaceDb {
|
||||
}
|
||||
|
||||
query! {
|
||||
pub(crate) async fn set_window_bounds(workspace_id: WorkspaceId, bounds: SerializedWindowsBounds, display: Uuid) -> Result<()> {
|
||||
pub(crate) async fn set_window_open_status(workspace_id: WorkspaceId, bounds: SerializedWindowBounds, display: Uuid) -> Result<()> {
|
||||
UPDATE workspaces
|
||||
SET window_state = ?2,
|
||||
window_x = ?3,
|
||||
@@ -841,14 +884,6 @@ impl WorkspaceDb {
|
||||
}
|
||||
}
|
||||
|
||||
query! {
|
||||
pub(crate) async fn set_fullscreen(workspace_id: WorkspaceId, fullscreen: bool) -> Result<()> {
|
||||
UPDATE workspaces
|
||||
SET fullscreen = ?2
|
||||
WHERE workspace_id = ?1
|
||||
}
|
||||
}
|
||||
|
||||
query! {
|
||||
pub(crate) async fn set_centered_layout(workspace_id: WorkspaceId, centered_layout: bool) -> Result<()> {
|
||||
UPDATE workspaces
|
||||
@@ -938,10 +973,9 @@ mod tests {
|
||||
id: WorkspaceId(1),
|
||||
location: LocalPaths::new(["/tmp", "/tmp2"]).into(),
|
||||
center_group: Default::default(),
|
||||
bounds: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
fullscreen: false,
|
||||
centered_layout: false,
|
||||
};
|
||||
|
||||
@@ -949,10 +983,9 @@ mod tests {
|
||||
id: WorkspaceId(2),
|
||||
location: LocalPaths::new(["/tmp"]).into(),
|
||||
center_group: Default::default(),
|
||||
bounds: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
fullscreen: false,
|
||||
centered_layout: false,
|
||||
};
|
||||
|
||||
@@ -1049,10 +1082,9 @@ mod tests {
|
||||
id: WorkspaceId(5),
|
||||
location: LocalPaths::new(["/tmp", "/tmp2"]).into(),
|
||||
center_group,
|
||||
bounds: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
fullscreen: false,
|
||||
centered_layout: false,
|
||||
};
|
||||
|
||||
@@ -1079,10 +1111,9 @@ mod tests {
|
||||
id: WorkspaceId(1),
|
||||
location: LocalPaths::new(["/tmp", "/tmp2"]).into(),
|
||||
center_group: Default::default(),
|
||||
bounds: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
fullscreen: false,
|
||||
centered_layout: false,
|
||||
};
|
||||
|
||||
@@ -1090,10 +1121,9 @@ mod tests {
|
||||
id: WorkspaceId(2),
|
||||
location: LocalPaths::new(["/tmp"]).into(),
|
||||
center_group: Default::default(),
|
||||
bounds: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
fullscreen: false,
|
||||
centered_layout: false,
|
||||
};
|
||||
|
||||
@@ -1128,10 +1158,9 @@ mod tests {
|
||||
id: WorkspaceId(3),
|
||||
location: LocalPaths::new(&["/tmp", "/tmp2"]).into(),
|
||||
center_group: Default::default(),
|
||||
bounds: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
fullscreen: false,
|
||||
centered_layout: false,
|
||||
};
|
||||
|
||||
@@ -1163,10 +1192,9 @@ mod tests {
|
||||
id: WorkspaceId(4),
|
||||
location: LocalPaths::new(workspace_id).into(),
|
||||
center_group: center_group.clone(),
|
||||
bounds: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
fullscreen: false,
|
||||
centered_layout: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::SerializedAxis;
|
||||
use super::{SerializedAxis, SerializedWindowBounds};
|
||||
use crate::{item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId};
|
||||
use anyhow::{Context, Result};
|
||||
use async_recursion::async_recursion;
|
||||
@@ -7,7 +7,7 @@ use db::sqlez::{
|
||||
bindable::{Bind, Column, StaticColumnCount},
|
||||
statement::Statement,
|
||||
};
|
||||
use gpui::{AsyncWindowContext, Bounds, DevicePixels, Model, Task, View, WeakView};
|
||||
use gpui::{AsyncWindowContext, Model, Task, View, WeakView};
|
||||
use project::Project;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
@@ -110,8 +110,7 @@ pub(crate) struct SerializedWorkspace {
|
||||
pub(crate) id: WorkspaceId,
|
||||
pub(crate) location: SerializedWorkspaceLocation,
|
||||
pub(crate) center_group: SerializedPaneGroup,
|
||||
pub(crate) bounds: Option<Bounds<DevicePixels>>,
|
||||
pub(crate) fullscreen: bool,
|
||||
pub(crate) window_bounds: Option<SerializedWindowBounds>,
|
||||
pub(crate) centered_layout: bool,
|
||||
pub(crate) display: Option<Uuid>,
|
||||
pub(crate) docks: DockStructure,
|
||||
|
||||
@@ -32,7 +32,7 @@ use gpui::{
|
||||
ElementId, Entity as _, EntityId, EventEmitter, FocusHandle, FocusableView, Global,
|
||||
GlobalElementId, KeyContext, Keystroke, LayoutId, ManagedView, Model, ModelContext,
|
||||
PathPromptOptions, Point, PromptLevel, Render, Size, Subscription, Task, View, WeakView,
|
||||
WindowHandle, WindowOptions,
|
||||
WindowBounds, WindowHandle, WindowOptions,
|
||||
};
|
||||
use item::{
|
||||
FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, PreviewTabsSettings,
|
||||
@@ -46,7 +46,7 @@ use node_runtime::NodeRuntime;
|
||||
use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
|
||||
pub use pane::*;
|
||||
pub use pane_group::*;
|
||||
use persistence::{model::SerializedWorkspace, SerializedWindowsBounds, DB};
|
||||
use persistence::{model::SerializedWorkspace, SerializedWindowBounds, DB};
|
||||
pub use persistence::{
|
||||
model::{ItemId, LocalPaths, SerializedDevServerProject, SerializedWorkspaceLocation},
|
||||
WorkspaceDb, DB as WORKSPACE_DB,
|
||||
@@ -785,29 +785,15 @@ impl Workspace {
|
||||
.await;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
if let Some(display) = cx.display() {
|
||||
let window_bounds = cx.window_bounds();
|
||||
let fullscreen = cx.is_fullscreen();
|
||||
|
||||
if let Some(display_uuid) = display.uuid().log_err() {
|
||||
// Only update the window bounds when not full screen,
|
||||
// so we can remember the last non-fullscreen bounds
|
||||
// across restarts
|
||||
if fullscreen {
|
||||
cx.background_executor()
|
||||
.spawn(DB.set_fullscreen(workspace_id, true))
|
||||
.detach_and_log_err(cx);
|
||||
} else if !cx.is_minimized() {
|
||||
cx.background_executor()
|
||||
.spawn(DB.set_fullscreen(workspace_id, false))
|
||||
.detach_and_log_err(cx);
|
||||
cx.background_executor()
|
||||
.spawn(DB.set_window_bounds(
|
||||
workspace_id,
|
||||
SerializedWindowsBounds(window_bounds),
|
||||
display_uuid,
|
||||
))
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
let window_bounds = cx.window_bounds();
|
||||
cx.background_executor()
|
||||
.spawn(DB.set_window_open_status(
|
||||
workspace_id,
|
||||
SerializedWindowBounds(window_bounds),
|
||||
display_uuid,
|
||||
))
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
}
|
||||
this.bounds_save_task_queued.take();
|
||||
@@ -947,30 +933,27 @@ impl Workspace {
|
||||
} else {
|
||||
let window_bounds_override = window_bounds_env_override();
|
||||
|
||||
let (bounds, display, fullscreen) = if let Some(bounds) = window_bounds_override {
|
||||
(Some(bounds), None, false)
|
||||
let (window_bounds, display) = if let Some(bounds) = window_bounds_override {
|
||||
(Some(WindowBounds::Windowed(bounds)), None)
|
||||
} else {
|
||||
let restorable_bounds = serialized_workspace
|
||||
.as_ref()
|
||||
.and_then(|workspace| {
|
||||
Some((workspace.display?, workspace.bounds?, workspace.fullscreen))
|
||||
})
|
||||
.and_then(|workspace| Some((workspace.display?, workspace.window_bounds?)))
|
||||
.or_else(|| {
|
||||
let (display, bounds, fullscreen) = DB.last_window().log_err()?;
|
||||
Some((display?, bounds?.0, fullscreen.unwrap_or(false)))
|
||||
let (display, window_bounds) = DB.last_window().log_err()?;
|
||||
Some((display?, window_bounds?))
|
||||
});
|
||||
|
||||
if let Some((serialized_display, bounds, fullscreen)) = restorable_bounds {
|
||||
(Some(bounds), Some(serialized_display), fullscreen)
|
||||
if let Some((serialized_display, serialized_status)) = restorable_bounds {
|
||||
(Some(serialized_status.0), Some(serialized_display))
|
||||
} else {
|
||||
(None, None, false)
|
||||
(None, None)
|
||||
}
|
||||
};
|
||||
|
||||
// Use the serialized workspace to construct the new window
|
||||
let mut options = cx.update(|cx| (app_state.build_window_options)(display, cx))?;
|
||||
options.bounds = bounds;
|
||||
options.fullscreen = fullscreen;
|
||||
options.window_bounds = window_bounds;
|
||||
let centered_layout = serialized_workspace
|
||||
.as_ref()
|
||||
.map(|w| w.centered_layout)
|
||||
@@ -3667,14 +3650,14 @@ impl Workspace {
|
||||
if let Some(location) = location {
|
||||
let center_group = build_serialized_pane_group(&self.center.root, cx);
|
||||
let docks = build_serialized_docks(self, cx);
|
||||
let window_bounds = Some(SerializedWindowBounds(cx.window_bounds()));
|
||||
let serialized_workspace = SerializedWorkspace {
|
||||
id: self.database_id,
|
||||
location,
|
||||
center_group,
|
||||
bounds: Default::default(),
|
||||
window_bounds,
|
||||
display: Default::default(),
|
||||
docks,
|
||||
fullscreen: cx.is_fullscreen(),
|
||||
centered_layout: self.centered_layout,
|
||||
};
|
||||
return cx.spawn(|_| persistence::DB.save_workspace(serialized_workspace));
|
||||
@@ -4867,7 +4850,8 @@ pub fn join_hosted_project(
|
||||
let window_bounds_override = window_bounds_env_override();
|
||||
cx.update(|cx| {
|
||||
let mut options = (app_state.build_window_options)(None, cx);
|
||||
options.bounds = window_bounds_override;
|
||||
options.window_bounds =
|
||||
window_bounds_override.map(|bounds| WindowBounds::Windowed(bounds));
|
||||
cx.open_window(options, |cx| {
|
||||
cx.new_view(|cx| {
|
||||
Workspace::new(Default::default(), project, app_state.clone(), cx)
|
||||
@@ -4931,7 +4915,8 @@ pub fn join_dev_server_project(
|
||||
let window_bounds_override = window_bounds_env_override();
|
||||
cx.update(|cx| {
|
||||
let mut options = (app_state.build_window_options)(None, cx);
|
||||
options.bounds = window_bounds_override;
|
||||
options.window_bounds =
|
||||
window_bounds_override.map(|bounds| WindowBounds::Windowed(bounds));
|
||||
cx.open_window(options, |cx| {
|
||||
cx.new_view(|cx| {
|
||||
Workspace::new(Default::default(), project, app_state.clone(), cx)
|
||||
@@ -4993,7 +4978,8 @@ pub fn join_in_room_project(
|
||||
let window_bounds_override = window_bounds_env_override();
|
||||
cx.update(|cx| {
|
||||
let mut options = (app_state.build_window_options)(None, cx);
|
||||
options.bounds = window_bounds_override;
|
||||
options.window_bounds =
|
||||
window_bounds_override.map(|bounds| WindowBounds::Windowed(bounds));
|
||||
cx.open_window(options, |cx| {
|
||||
cx.new_view(|cx| {
|
||||
Workspace::new(Default::default(), project, app_state.clone(), cx)
|
||||
|
||||
@@ -96,13 +96,12 @@ pub fn build_window_options(display_uuid: Option<Uuid>, cx: &mut AppContext) ->
|
||||
appears_transparent: true,
|
||||
traffic_light_position: Some(point(px(9.0), px(9.0))),
|
||||
}),
|
||||
bounds: None,
|
||||
window_bounds: None,
|
||||
focus: false,
|
||||
show: false,
|
||||
kind: WindowKind::Normal,
|
||||
is_movable: true,
|
||||
display_id: display.map(|display| display.id()),
|
||||
fullscreen: false,
|
||||
window_background: cx.theme().window_background_appearance(),
|
||||
app_id: Some(app_id.to_owned()),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user