Merge pull request #1485 from zed-industries/fullscreen-workspace-title-padding

Fullscreen workspace title padding
This commit is contained in:
Mikayla Maki 2022-08-09 17:02:26 -07:00 committed by GitHub
commit c303c4e8f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 445 additions and 397 deletions

File diff suppressed because it is too large Load diff

View 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();
}
}
}
}
}
}
}
}

View file

@ -112,6 +112,7 @@ pub trait Window: WindowContext {
fn on_event(&mut self, callback: Box<dyn FnMut(Event) -> bool>); 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_active_status_change(&mut self, callback: Box<dyn FnMut(bool)>);
fn on_resize(&mut self, callback: Box<dyn FnMut()>); 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_should_close(&mut self, callback: Box<dyn FnMut() -> bool>);
fn on_close(&mut self, callback: Box<dyn FnOnce()>); fn on_close(&mut self, callback: Box<dyn FnOnce()>);
fn set_input_handler(&mut self, input_handler: Box<dyn InputHandler>); fn set_input_handler(&mut self, input_handler: Box<dyn InputHandler>);

View file

@ -128,6 +128,14 @@ unsafe fn build_classes() {
sel!(windowDidResize:), sel!(windowDidResize:),
window_did_resize as extern "C" fn(&Object, Sel, id), 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( decl.add_method(
sel!(windowDidBecomeKey:), sel!(windowDidBecomeKey:),
window_did_change_key_status as extern "C" fn(&Object, Sel, id), 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>>, event_callback: Option<Box<dyn FnMut(Event) -> bool>>,
activate_callback: Option<Box<dyn FnMut(bool)>>, activate_callback: Option<Box<dyn FnMut(bool)>>,
resize_callback: Option<Box<dyn FnMut()>>, resize_callback: Option<Box<dyn FnMut()>>,
fullscreen_callback: Option<Box<dyn FnMut(bool)>>,
should_close_callback: Option<Box<dyn FnMut() -> bool>>, should_close_callback: Option<Box<dyn FnMut() -> bool>>,
close_callback: Option<Box<dyn FnOnce()>>, close_callback: Option<Box<dyn FnOnce()>>,
input_handler: Option<Box<dyn InputHandler>>, input_handler: Option<Box<dyn InputHandler>>,
@ -368,6 +377,7 @@ impl Window {
should_close_callback: None, should_close_callback: None,
close_callback: None, close_callback: None,
activate_callback: None, activate_callback: None,
fullscreen_callback: None,
input_handler: None, input_handler: None,
pending_key_down: None, pending_key_down: None,
performed_key_equivalent: false, performed_key_equivalent: false,
@ -467,6 +477,10 @@ impl platform::Window for Window {
self.0.as_ref().borrow_mut().resize_callback = Some(callback); 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>) { fn on_should_close(&mut self, callback: Box<dyn FnMut() -> bool>) {
self.0.as_ref().borrow_mut().should_close_callback = Some(callback); 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(); 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) { extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) {
let is_active = if selector == sel!(windowDidBecomeKey:) { let is_active = if selector == sel!(windowDidBecomeKey:) {
true true

View file

@ -37,6 +37,7 @@ pub struct Window {
event_handlers: Vec<Box<dyn FnMut(super::Event) -> bool>>, event_handlers: Vec<Box<dyn FnMut(super::Event) -> bool>>,
resize_handlers: Vec<Box<dyn FnMut()>>, resize_handlers: Vec<Box<dyn FnMut()>>,
close_handlers: Vec<Box<dyn FnOnce()>>, 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) active_status_change_handlers: Vec<Box<dyn FnMut(bool)>>,
pub(crate) should_close_handler: Option<Box<dyn FnMut() -> bool>>, pub(crate) should_close_handler: Option<Box<dyn FnMut() -> bool>>,
pub(crate) title: Option<String>, pub(crate) title: Option<String>,
@ -199,6 +200,7 @@ impl Window {
close_handlers: Default::default(), close_handlers: Default::default(),
should_close_handler: Default::default(), should_close_handler: Default::default(),
active_status_change_handlers: Default::default(), active_status_change_handlers: Default::default(),
fullscreen_handlers: Default::default(),
scale_factor: 1.0, scale_factor: 1.0,
current_scene: None, current_scene: None,
title: None, title: None,
@ -253,6 +255,10 @@ impl super::Window for Window {
self.active_status_change_handlers.push(callback); 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()>) { fn on_resize(&mut self, callback: Box<dyn FnMut()>) {
self.resize_handlers.push(callback); self.resize_handlers.push(callback);
} }

View file

@ -13,11 +13,11 @@ use crate::{
ReadModel, ReadView, RenderContext, RenderParams, Scene, UpgradeModelHandle, UpgradeViewHandle, ReadModel, ReadView, RenderContext, RenderParams, Scene, UpgradeModelHandle, UpgradeViewHandle,
View, ViewHandle, WeakModelHandle, WeakViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
}; };
use collections::{HashMap, HashSet};
use pathfinder_geometry::vector::{vec2f, Vector2F}; use pathfinder_geometry::vector::{vec2f, Vector2F};
use serde_json::json; use serde_json::json;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
collections::{HashMap, HashSet},
marker::PhantomData, marker::PhantomData,
ops::{Deref, DerefMut, Range}, ops::{Deref, DerefMut, Range},
sync::Arc, sync::Arc,
@ -52,7 +52,7 @@ impl Presenter {
Self { Self {
window_id, window_id,
rendered_views: cx.render_views(window_id, titlebar_height), rendered_views: cx.render_views(window_id, titlebar_height),
parents: HashMap::new(), parents: Default::default(),
cursor_regions: Default::default(), cursor_regions: Default::default(),
mouse_regions: Default::default(), mouse_regions: Default::default(),
font_cache, font_cache,

View file

@ -823,6 +823,8 @@ enum FollowerItem {
impl Workspace { impl Workspace {
pub fn new(project: ModelHandle<Project>, cx: &mut ViewContext<Self>) -> Self { 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) cx.observe_window_activation(Self::on_window_activation_changed)
.detach(); .detach();
cx.observe(&project, |_, _, cx| cx.notify()).detach(); cx.observe(&project, |_, _, cx| cx.notify()).detach();
@ -1856,6 +1858,17 @@ impl Workspace {
worktree_root_names.push_str(name); 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( ConstrainedBox::new(
Container::new( Container::new(
Stack::new() Stack::new()
@ -1883,7 +1896,7 @@ impl Workspace {
) )
.boxed(), .boxed(),
) )
.with_style(theme.workspace.titlebar.container) .with_style(container_theme)
.boxed(), .boxed(),
) )
.with_height(theme.workspace.titlebar.height) .with_height(theme.workspace.titlebar.height)