mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-25 01:34:02 +00:00
Merge pull request #1485 from zed-industries/fullscreen-workspace-title-padding
Fullscreen workspace title padding
This commit is contained in:
commit
c303c4e8f9
7 changed files with 445 additions and 397 deletions
File diff suppressed because it is too large
Load diff
106
crates/gpui/src/app/callback_collection.rs
Normal file
106
crates/gpui/src/app/callback_collection.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use std::sync::Arc;
|
||||
use std::{hash::Hash, sync::Weak};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use collections::{btree_map, BTreeMap, HashMap};
|
||||
|
||||
use crate::MutableAppContext;
|
||||
|
||||
pub type Mapping<K, F> = Mutex<HashMap<K, BTreeMap<usize, Option<F>>>>;
|
||||
|
||||
pub struct CallbackCollection<K: Hash + Eq, F> {
|
||||
internal: Arc<Mapping<K, F>>,
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq, F> Clone for CallbackCollection<K, F> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
internal: self.internal.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Copy, F> Default for CallbackCollection<K, F> {
|
||||
fn default() -> Self {
|
||||
CallbackCollection {
|
||||
internal: Arc::new(Mutex::new(Default::default())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Copy, F> CallbackCollection<K, F> {
|
||||
pub fn downgrade(&self) -> Weak<Mapping<K, F>> {
|
||||
Arc::downgrade(&self.internal)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.internal.lock().is_empty()
|
||||
}
|
||||
|
||||
pub fn add_callback(&mut self, id: K, subscription_id: usize, callback: F) {
|
||||
self.internal
|
||||
.lock()
|
||||
.entry(id)
|
||||
.or_default()
|
||||
.insert(subscription_id, Some(callback));
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: K) {
|
||||
self.internal.lock().remove(&id);
|
||||
}
|
||||
|
||||
pub fn add_or_remove_callback(&mut self, id: K, subscription_id: usize, callback: F) {
|
||||
match self
|
||||
.internal
|
||||
.lock()
|
||||
.entry(id)
|
||||
.or_default()
|
||||
.entry(subscription_id)
|
||||
{
|
||||
btree_map::Entry::Vacant(entry) => {
|
||||
entry.insert(Some(callback));
|
||||
}
|
||||
|
||||
btree_map::Entry::Occupied(entry) => {
|
||||
// TODO: This seems like it should never be called because no code
|
||||
// should ever attempt to remove an existing callback
|
||||
debug_assert!(entry.get().is_none());
|
||||
entry.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_and_cleanup<C: FnMut(&mut F, &mut MutableAppContext) -> bool>(
|
||||
&mut self,
|
||||
id: K,
|
||||
cx: &mut MutableAppContext,
|
||||
mut call_callback: C,
|
||||
) {
|
||||
let callbacks = self.internal.lock().remove(&id);
|
||||
if let Some(callbacks) = callbacks {
|
||||
for (subscription_id, callback) in callbacks {
|
||||
if let Some(mut callback) = callback {
|
||||
let alive = call_callback(&mut callback, cx);
|
||||
if alive {
|
||||
match self
|
||||
.internal
|
||||
.lock()
|
||||
.entry(id)
|
||||
.or_default()
|
||||
.entry(subscription_id)
|
||||
{
|
||||
btree_map::Entry::Vacant(entry) => {
|
||||
entry.insert(Some(callback));
|
||||
}
|
||||
btree_map::Entry::Occupied(entry) => {
|
||||
entry.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -112,6 +112,7 @@ pub trait Window: WindowContext {
|
|||
fn on_event(&mut self, callback: Box<dyn FnMut(Event) -> bool>);
|
||||
fn on_active_status_change(&mut self, callback: Box<dyn FnMut(bool)>);
|
||||
fn on_resize(&mut self, callback: Box<dyn FnMut()>);
|
||||
fn on_fullscreen(&mut self, callback: Box<dyn FnMut(bool)>);
|
||||
fn on_should_close(&mut self, callback: Box<dyn FnMut() -> bool>);
|
||||
fn on_close(&mut self, callback: Box<dyn FnOnce()>);
|
||||
fn set_input_handler(&mut self, input_handler: Box<dyn InputHandler>);
|
||||
|
|
|
@ -128,6 +128,14 @@ unsafe fn build_classes() {
|
|||
sel!(windowDidResize:),
|
||||
window_did_resize 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!(windowWillExitFullScreen:),
|
||||
window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(windowDidBecomeKey:),
|
||||
window_did_change_key_status as extern "C" fn(&Object, Sel, id),
|
||||
|
@ -276,6 +284,7 @@ struct WindowState {
|
|||
event_callback: Option<Box<dyn FnMut(Event) -> bool>>,
|
||||
activate_callback: Option<Box<dyn FnMut(bool)>>,
|
||||
resize_callback: Option<Box<dyn FnMut()>>,
|
||||
fullscreen_callback: Option<Box<dyn FnMut(bool)>>,
|
||||
should_close_callback: Option<Box<dyn FnMut() -> bool>>,
|
||||
close_callback: Option<Box<dyn FnOnce()>>,
|
||||
input_handler: Option<Box<dyn InputHandler>>,
|
||||
|
@ -368,6 +377,7 @@ impl Window {
|
|||
should_close_callback: None,
|
||||
close_callback: None,
|
||||
activate_callback: None,
|
||||
fullscreen_callback: None,
|
||||
input_handler: None,
|
||||
pending_key_down: None,
|
||||
performed_key_equivalent: false,
|
||||
|
@ -467,6 +477,10 @@ impl platform::Window for Window {
|
|||
self.0.as_ref().borrow_mut().resize_callback = Some(callback);
|
||||
}
|
||||
|
||||
fn on_fullscreen(&mut self, callback: Box<dyn FnMut(bool)>) {
|
||||
self.0.as_ref().borrow_mut().fullscreen_callback = Some(callback);
|
||||
}
|
||||
|
||||
fn on_should_close(&mut self, callback: Box<dyn FnMut() -> bool>) {
|
||||
self.0.as_ref().borrow_mut().should_close_callback = Some(callback);
|
||||
}
|
||||
|
@ -908,6 +922,24 @@ extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
|
|||
window_state.as_ref().borrow().move_traffic_light();
|
||||
}
|
||||
|
||||
extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
||||
window_fullscreen_changed(this, true);
|
||||
}
|
||||
|
||||
extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) {
|
||||
window_fullscreen_changed(this, false);
|
||||
}
|
||||
|
||||
fn window_fullscreen_changed(this: &Object, is_fullscreen: bool) {
|
||||
let window_state = unsafe { get_window_state(this) };
|
||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
||||
if let Some(mut callback) = window_state_borrow.fullscreen_callback.take() {
|
||||
drop(window_state_borrow);
|
||||
callback(is_fullscreen);
|
||||
window_state.borrow_mut().fullscreen_callback = Some(callback);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) {
|
||||
let is_active = if selector == sel!(windowDidBecomeKey:) {
|
||||
true
|
||||
|
|
|
@ -37,6 +37,7 @@ pub struct Window {
|
|||
event_handlers: Vec<Box<dyn FnMut(super::Event) -> bool>>,
|
||||
resize_handlers: Vec<Box<dyn FnMut()>>,
|
||||
close_handlers: Vec<Box<dyn FnOnce()>>,
|
||||
fullscreen_handlers: Vec<Box<dyn FnMut(bool)>>,
|
||||
pub(crate) active_status_change_handlers: Vec<Box<dyn FnMut(bool)>>,
|
||||
pub(crate) should_close_handler: Option<Box<dyn FnMut() -> bool>>,
|
||||
pub(crate) title: Option<String>,
|
||||
|
@ -199,6 +200,7 @@ impl Window {
|
|||
close_handlers: Default::default(),
|
||||
should_close_handler: Default::default(),
|
||||
active_status_change_handlers: Default::default(),
|
||||
fullscreen_handlers: Default::default(),
|
||||
scale_factor: 1.0,
|
||||
current_scene: None,
|
||||
title: None,
|
||||
|
@ -253,6 +255,10 @@ impl super::Window for Window {
|
|||
self.active_status_change_handlers.push(callback);
|
||||
}
|
||||
|
||||
fn on_fullscreen(&mut self, callback: Box<dyn FnMut(bool)>) {
|
||||
self.fullscreen_handlers.push(callback)
|
||||
}
|
||||
|
||||
fn on_resize(&mut self, callback: Box<dyn FnMut()>) {
|
||||
self.resize_handlers.push(callback);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,11 @@ use crate::{
|
|||
ReadModel, ReadView, RenderContext, RenderParams, Scene, UpgradeModelHandle, UpgradeViewHandle,
|
||||
View, ViewHandle, WeakModelHandle, WeakViewHandle,
|
||||
};
|
||||
use collections::{HashMap, HashSet};
|
||||
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||
use serde_json::json;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
sync::Arc,
|
||||
|
@ -52,7 +52,7 @@ impl Presenter {
|
|||
Self {
|
||||
window_id,
|
||||
rendered_views: cx.render_views(window_id, titlebar_height),
|
||||
parents: HashMap::new(),
|
||||
parents: Default::default(),
|
||||
cursor_regions: Default::default(),
|
||||
mouse_regions: Default::default(),
|
||||
font_cache,
|
||||
|
|
|
@ -823,6 +823,8 @@ enum FollowerItem {
|
|||
|
||||
impl Workspace {
|
||||
pub fn new(project: ModelHandle<Project>, cx: &mut ViewContext<Self>) -> Self {
|
||||
cx.observe_fullscreen(|_, _, cx| cx.notify()).detach();
|
||||
|
||||
cx.observe_window_activation(Self::on_window_activation_changed)
|
||||
.detach();
|
||||
cx.observe(&project, |_, _, cx| cx.notify()).detach();
|
||||
|
@ -1856,6 +1858,17 @@ impl Workspace {
|
|||
worktree_root_names.push_str(name);
|
||||
}
|
||||
|
||||
// TODO: There should be a better system in place for this
|
||||
// (https://github.com/zed-industries/zed/issues/1290)
|
||||
let is_fullscreen = cx.window_is_fullscreen(cx.window_id());
|
||||
let container_theme = if is_fullscreen {
|
||||
let mut container_theme = theme.workspace.titlebar.container;
|
||||
container_theme.padding.left = container_theme.padding.right;
|
||||
container_theme
|
||||
} else {
|
||||
theme.workspace.titlebar.container
|
||||
};
|
||||
|
||||
ConstrainedBox::new(
|
||||
Container::new(
|
||||
Stack::new()
|
||||
|
@ -1883,7 +1896,7 @@ impl Workspace {
|
|||
)
|
||||
.boxed(),
|
||||
)
|
||||
.with_style(theme.workspace.titlebar.container)
|
||||
.with_style(container_theme)
|
||||
.boxed(),
|
||||
)
|
||||
.with_height(theme.workspace.titlebar.height)
|
||||
|
|
Loading…
Reference in a new issue