Skip to content

Commit

Permalink
Stop using NSFullSizeContentViewWindowMask to get borderless windows,
Browse files Browse the repository at this point in the history
because that disables the swap interval.

This hack is very simple but a little evil. We get the superview of the
content view, which is the `NSThemeFrame`, and install an OpenGL context
into it.  `NSThemeFrame` is a private class, but we never speak its
name, we get to it with public APIs, and we only call public `NSView`
APIs on it, so this seems OK in terms of being supported by Apple going
forward.

Additionally, we remove the standard window buttons so that they
disappear and the user can't click them. This can also be done using
public APIs.

The reason for using this hack as opposed to
`NSFullSizeContentViewWindowMask` is that the latter forces the window
to be Core Animation-backed, which results in us rendering to an off
screen surface. Not only does this inject another compositor into the
system, but it also results in us rendering to an off-screen surface,
disabling the swap interval.

This depends on a `cocoa-rs` upgrade to add a binding to the `-[NSView
superview]` method.

Note that the top edge of the window is not rounded, although the shadow
is. Applications that wish to use this mode will need to round the top
edge themselves if they wish. (This is how Cocoa internally works:
rounding is done by the app, not the window manager.)

This should fix servo/servo#9431.
  • Loading branch information
pcwalton committed Feb 3, 2016
1 parent d78affc commit 5731ad2
Showing 1 changed file with 40 additions and 10 deletions.
50 changes: 40 additions & 10 deletions src/api/cocoa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ impl Window {
Some(window) => window,
None => { return Err(OsError(format!("Couldn't create NSWindow"))); },
};
let view = match Window::create_view(*window) {
let view = match Window::get_or_create_view(*window, win_attribs.decorations) {
Some(view) => view,
None => { return Err(OsError(format!("Couldn't create NSView"))); },
};
Expand Down Expand Up @@ -412,8 +412,7 @@ impl Window {
NSClosableWindowMask as NSUInteger |
NSMiniaturizableWindowMask as NSUInteger |
NSResizableWindowMask as NSUInteger |
NSTitledWindowMask as NSUInteger |
NSFullSizeContentViewWindowMask as NSUInteger
NSTitledWindowMask as NSUInteger
};

let window = IdRef::new(NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
Expand All @@ -428,8 +427,24 @@ impl Window {
window.setAcceptsMouseMovedEvents_(YES);

if !attrs.decorations {
// Make titles invisible so that nothing is drawn.
window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden);
window.setTitlebarAppearsTransparent_(YES);

// Get rid of all the buttons so that they won't be drawn and the user can't
// click them.
for &button_type in &[
NSWindowButton::NSWindowCloseButton,
NSWindowButton::NSWindowMiniaturizeButton,
NSWindowButton::NSWindowZoomButton,
NSWindowButton::NSWindowToolbarButton,
NSWindowButton::NSWindowFullScreenButton,
] {
if let Some(button) =
IdRef::new(window.standardWindowButton_(button_type)).non_nil() {
button.removeFromSuperview()
}
}
}

if screen.is_some() {
Expand All @@ -443,14 +458,29 @@ impl Window {
}
}

fn create_view(window: id) -> Option<IdRef> {
fn get_or_create_view(window: id, decorations: bool) -> Option<IdRef> {
unsafe {
let view = IdRef::new(NSView::alloc(nil).init());
view.non_nil().map(|view| {
view.setWantsBestResolutionOpenGLSurface_(YES);
window.setContentView_(*view);
view
})
if decorations {
let view = IdRef::new(NSView::alloc(nil).init());
return view.non_nil().map(|view| {
view.setWantsBestResolutionOpenGLSurface_(YES);
window.setContentView_(*view);
view
})
}

// This hack is a little evil. We get the superview of the content view, which is the
// `NSThemeFrame`, and install an OpenGL context into it. `NSThemeFrame` is a private
// class, but we only call public `NSView` APIs on it here, so this seems OK.
//
// The reason for using this hack as opposed to `NSFullSizeContentViewWindowMask` is
// that the latter forces the window to be Core Animation-backed, which results in us
// rendering to an off screen surface. Not only does this inject another compositor
// into the system, but it also results in us rendering to an off-screen surface,
// disabling the swap interval.
let view = window.contentView().superview();
view.setWantsBestResolutionOpenGLSurface_(YES);
Some(IdRef::new(view))
}
}

Expand Down

0 comments on commit 5731ad2

Please sign in to comment.