Skip to content

Commit

Permalink
Inset Mac OS traffic lights (#513)
Browse files Browse the repository at this point in the history
* new example

* feat(macos): Fixed the traffic light example

Traffic lights get refreshed. Still artifacts visible

* feat(macos): Implemented and exposed a traffic light reposition method for Builder and Window

* fix(macos): fixed the issue with the artifact on resize

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update src/platform_impl/macos/window.rs

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Delete macos_traffic_lights.rs

Example not needed

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* Update window.rs

Deleted outdated TODO

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* refactor: Replaced type of inset with LogicalSize + docs

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* fixes

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* revert accidental commit

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* add back example

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* fix(macos): traffic light offset now works as expected

The set_traffic_light_offset() method on window was removed and only the builder function now has to be called to set the offset. No more manual event handling is needed.

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* refactor(macos): removed the traffic light example

the example is no longer needed as the api design is now clear and only one method call is needed to set the inset

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* feat(macos): added set_traffic_light_position back in

the set_traffic_light_position on window will now work as expected. I.e. only one call is necessary

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* delete comment

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* revert(macos): reverted accidental deletion of null check

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* refactor(macos): changed traffic light inset to LogicalPosition<f64>

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* refactor(macos): changed pulic api back to Position

Also unified the api to always use inset instead of position

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* cleanup after rebase

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>

* more cleanup

* fix macos

---------

Signed-off-by: amrbashir <amr.bashir2015@gmail.com>
Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Co-authored-by: Jonas Kruckenberg <iterpre@protonmail.com>
  • Loading branch information
3 people authored Oct 26, 2023
1 parent bd8bafe commit f7e4991
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 3 deletions.
17 changes: 16 additions & 1 deletion src/platform/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use std::os::raw::c_void;

use crate::{
dpi::LogicalSize,
dpi::{LogicalSize, Position},
event_loop::{EventLoop, EventLoopWindowTarget},
monitor::MonitorHandle,
platform_impl::{get_aux_state_mut, Parent},
Expand Down Expand Up @@ -49,6 +49,8 @@ pub trait WindowExtMacOS {
/// Sets whether or not the window has shadow.
fn set_has_shadow(&self, has_shadow: bool);

/// Set the window traffic light position relative to the upper left corner
fn set_traffic_light_inset<P: Into<Position>>(&self, position: P);
/// Put the window in a state which indicates a file save is required.
///
/// <https://developer.apple.com/documentation/appkit/nswindow/1419311-isdocumentedited>
Expand Down Expand Up @@ -105,6 +107,11 @@ impl WindowExtMacOS for Window {
self.window.set_has_shadow(has_shadow)
}

#[inline]
fn set_traffic_light_inset<P: Into<Position>>(&self, position: P) {
self.window.set_traffic_light_inset(position)
}

#[inline]
fn set_is_document_edited(&self, edited: bool) {
self.window.set_is_document_edited(edited)
Expand Down Expand Up @@ -194,6 +201,8 @@ pub trait WindowBuilderExtMacOS {
fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
/// Sets whether or not the window has shadow.
fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
/// Sets the traffic light position to (x, y) relative to the upper left corner
fn with_traffic_light_inset<P: Into<Position>>(self, inset: P) -> WindowBuilder;
/// Sets whether the system can automatically organize windows into tabs.
fn with_automatic_window_tabbing(self, automatic_tabbing: bool) -> WindowBuilder;
/// Defines the window [tabbing identifier].
Expand Down Expand Up @@ -266,6 +275,12 @@ impl WindowBuilderExtMacOS for WindowBuilder {
self
}

#[inline]
fn with_traffic_light_inset<P: Into<Position>>(mut self, inset: P) -> WindowBuilder {
self.platform_specific.traffic_light_inset = Some(inset.into());
self
}

#[inline]
fn with_automatic_window_tabbing(mut self, automatic_tabbing: bool) -> WindowBuilder {
self.platform_specific.automatic_tabbing = automatic_tabbing;
Expand Down
35 changes: 34 additions & 1 deletion src/platform_impl/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{
};

use cocoa::{
appkit::{NSApp, NSEvent, NSEventModifierFlags, NSEventPhase, NSView, NSWindow},
appkit::{NSApp, NSEvent, NSEventModifierFlags, NSEventPhase, NSView, NSWindow, NSWindowButton},
base::{id, nil},
foundation::{NSInteger, NSPoint, NSRect, NSSize, NSString, NSUInteger},
};
Expand Down Expand Up @@ -70,6 +70,7 @@ pub(super) struct ViewState {
pub(super) modifiers: ModifiersState,
phys_modifiers: HashSet<KeyCode>,
tracking_rect: Option<NSInteger>,
pub(super) traffic_light_inset: Option<LogicalPosition<f64>>,
}

impl ViewState {
Expand All @@ -91,6 +92,7 @@ pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<CursorState>>) {
modifiers: Default::default(),
phys_modifiers: Default::default(),
tracking_rect: None,
traffic_light_inset: None,
};
unsafe {
// This is free'd in `dealloc`
Expand Down Expand Up @@ -384,6 +386,11 @@ extern "C" fn draw_rect(this: &Object, _sel: Sel, rect: NSRect) {
let state_ptr: *mut c_void = *this.get_ivar("taoState");
let state = &mut *(state_ptr as *mut ViewState);

if let Some(position) = state.traffic_light_inset {
let window = state.ns_window;
inset_traffic_lights(window, position);
}

AppState::handle_redraw(WindowId(get_window_id(state.ns_window)));

let superclass = util::superclass(this);
Expand Down Expand Up @@ -1176,3 +1183,29 @@ extern "C" fn wants_key_down_for_event(_this: &Object, _sel: Sel, _event: id) ->
extern "C" fn accepts_first_mouse(_this: &Object, _sel: Sel, _event: id) -> BOOL {
YES
}

pub unsafe fn inset_traffic_lights<W: NSWindow + Copy>(window: W, position: LogicalPosition<f64>) {
let (x, y) = (position.x, position.y);

let close = window.standardWindowButton_(NSWindowButton::NSWindowCloseButton);
let miniaturize = window.standardWindowButton_(NSWindowButton::NSWindowMiniaturizeButton);
let zoom = window.standardWindowButton_(NSWindowButton::NSWindowZoomButton);

let title_bar_container_view = close.superview().superview();

let close_rect = NSView::frame(close);
let title_bar_frame_height = close_rect.size.height + y;
let mut title_bar_rect = NSView::frame(title_bar_container_view);
title_bar_rect.size.height = title_bar_frame_height;
title_bar_rect.origin.y = window.frame().size.height - title_bar_frame_height;
let _: () = msg_send![title_bar_container_view, setFrame: title_bar_rect];

let window_buttons = vec![close, miniaturize, zoom];
let space_between = NSView::frame(miniaturize).origin.x - close_rect.origin.x;

for (i, button) in window_buttons.into_iter().enumerate() {
let mut rect = NSView::frame(button);
rect.origin.x = x + (i as f64 * space_between);
button.setFrameOrigin(rect.origin);
}
}
22 changes: 21 additions & 1 deletion src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use objc::{
runtime::{Class, Object, Sel, BOOL, NO, YES},
};

use super::util::ns_string_to_rust;
use super::{util::ns_string_to_rust, view::ViewState};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id(pub usize);
Expand Down Expand Up @@ -91,6 +91,7 @@ pub struct PlatformSpecificWindowBuilderAttributes {
pub resize_increments: Option<LogicalSize<f64>>,
pub disallow_hidpi: bool,
pub has_shadow: bool,
pub traffic_light_inset: Option<Position>,
pub automatic_tabbing: bool,
pub tabbing_identifier: Option<String>,
}
Expand All @@ -109,6 +110,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
resize_increments: None,
disallow_hidpi: false,
has_shadow: true,
traffic_light_inset: None,
automatic_tabbing: true,
tabbing_identifier: None,
}
Expand All @@ -125,6 +127,14 @@ unsafe fn create_view(
ns_view.setWantsBestResolutionOpenGLSurface_(YES);
}

if let Some(position) = pl_attribs.traffic_light_inset {
let state_ptr: *mut c_void = *(**ns_view).get_ivar("taoState");
let state = &mut *(state_ptr as *mut ViewState);
let scale_factor = NSWindow::backingScaleFactor(ns_window);
let position = position.to_logical(scale_factor);
state.traffic_light_inset = Some(position);
}

// On Mojave, views automatically become layer-backed shortly after being added to
// a window. Changing the layer-backedness of a view breaks the association between
// the view and its associated OpenGL context. To work around this, on Mojave we
Expand Down Expand Up @@ -1547,6 +1557,16 @@ impl WindowExtMacOS for UnownedWindow {
}
}

#[inline]
fn set_traffic_light_inset<P: Into<Position>>(&self, position: P) {
let position: Position = position.into();
unsafe {
let state_ptr: *mut c_void = *(**self.ns_view).get_ivar("taoState");
let state = &mut *(state_ptr as *mut ViewState);
state.traffic_light_inset = Some(position.to_logical(self.scale_factor()));
}
}

#[inline]
fn set_is_document_edited(&self, edited: bool) {
unsafe {
Expand Down

0 comments on commit f7e4991

Please sign in to comment.