How can I use the native window controls and behaviour inside a custom window title bar or component?
I’m trying to have some of my components fill the height of the window and be ‘inside’ the title bar (as shown below) but I’m not entirely sure how to go about it. Using the JUCE Titlebar and just faking the look of the icons seems to change the default behaviour for the window controls which isn’t my desired behaviour.
Got this bit of ObjC code to achieve this on the Mac. Is there anywhere in JUCE to achieve a similar functionality using just C++?
window.titlebarAppearsTransparent = true
window.titleVisibility = .Hidden
window.styleMask |= NSFullSizeContentViewWindowMask
AFAIK you can set the titlebar height to 0 to hide it:
DocumentWindow::setTitleBarHeight (0); and set required buttons to 0 when you construct the window.
Is this what you are after?
Doesn’t that remove the Window control buttons completely? (I’m away from a Mac to test) I’m looking to have the window controls overlayed on my JUCE component
Well yes, I thought that’s what the ObjC calls do, that you posted as reference… maybe I understood the goal wrong then.
I was wondering if there was already a cross platform solution in JUCE as I’d ideally like a similar behaviour on windows
Edit: This is the sort of effect I’m looking for
Now I am confused, yes, the code I gave will remove the title bar on windows, mac and linux.
You could add your own buttons then inside the window and call setFullScreen() or what is appropriate.
The image makes it clear now, thanks.
I don’t know, if you can set a background image behind the original titlebar though…
Good luck
I see it is an old topic but …
why when I use setUsingNativeTitleBar (false);
I cannot resize the window anymore ?
I would like to get rid of the native titlebar, but keep the window resizability. setResizable(true) does what its name suggests as long as I have setUsingNativeTitleBar set to true. Not a big issue overall but as I came across this behaviour I would like to understand how it works …is there a workaround so to have the window without the nativeBar on top AND resizable? I have turned my window into a DocumentWindow (it was a ResizableWindow) just to call setTitleBarHeight(0), as Daniel suggested, but calling this method doesn’t make the title bar disappear … ?
Hey All, sorry to revive this old thread.
We’re also looking for a similar effect (more precisely, we just want to be able to set a custom colour for the title bar) and I was wondering what’s the best way to do it…
Initially I started by setting setUsingNativeTitleBar (false) and drawing my own title bar via the L&F methods… but then I realised that I would also need to “manually” draw the minimise/maximise/close buttons which probably isn’t ideal (what if Apple changes them in future versions of the OS? And why having to draw them anyway since they are a “standard” widget?).
Really all we need is a standard title bar, but with the ability to set a custom colour for it. All buttons & other controls remain native…
Is there any way this can be done directly in JUCE without having to touch the ObjectiveC?
Thanks!
In case anybody else is interested, we managed to put together a little JUCE patch that adds a method to make the native macOS title bar background transparent while keeping the native controls:
TopLevelWindow::setNativeTitleBarTransparent (bool)
It basically does two things:
- make the title bar background transparent
- make the window content “full-size” so it fills the whole area including where the title bar is
Combined, those two changes give us the impression of having a “custom title bar with native controls”.
Under the hood it’s pretty much what’s been suggested earlier in this post and elsewhere - all I did was to package it nicely to make it easy to use and to opt in/out as needed.
Here’s the commit to our JUCE fork:
Happy to submit it as an “official” JUCE patch if there’s any interest, otherwise feel free grab whatever part you need ![]()
I was working with the patch provided above (FYI: the link does not work anymore, because the repository moved, but here is a corrected one Mac-only: add ability to make native title bar transparent · jcredland/JUCE_old@86edfd4 · GitHub )
but it had the flaw of the window not moving anymore when dragged on the “title bar”, which technically no longer existed.
This is because of the JUCE implementation of the MacOS native NSWindow class in `juce::NSViewComponentPeer`. They are overwriting the functions mouseDown, mouseUp, mouseDrag etc. without making a super-call, which cancels the MacOS native window dragging behaviour. Changing this behaviour, is resulting in all the native window dragging options to be available again, like snapping.
Since JUCE is doing the “implementation” of the MacOS window handle using reflection, the resulting change to do the super call is a bit of a syntactical nightmare.
From cf0679b9bd881e86495f5773e1eedbf7d79c8900 Mon Sep 17 00:00:00 2001
From: Rincewind <me@rincewind.com>
Date: Wed, 21 Oct 2026 00:59:17 +0200
Subject: [PATCH] Added super calls to NSViewComponentPeer for mouseDown,
mouseDragged, mouseUp resulting in better window dragging behaviour
---
.../native/juce_NSViewComponentPeer_mac.mm | 20 ++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm b/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm
index af7a7ddfa..71d6f4d49 100644
--- a/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm
+++ b/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm
@@ -2631,9 +2631,9 @@ private:
(owner->*func) (std::forward<Args> (args)...);
}
- static void mouseDragged (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDrag, ev); }
- static void asyncMouseDown (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDown, ev); }
- static void asyncMouseUp (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseUp, ev); }
+ static void mouseDragged (id self, SEL s, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDrag, ev); __reflectionBasedSuperCall(self, s, ev); }
+ static void asyncMouseDown (id self, SEL s, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDown, ev); __reflectionBasedSuperCall(self, s, ev); }
+ static void asyncMouseUp (id self, SEL s, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseUp, ev); __reflectionBasedSuperCall(self, s, ev); }
static void draggingExited (id self, SEL, id<NSDraggingInfo> sender) { callOnOwner (self, &NSViewComponentPeer::sendDragCallback, &NSViewComponentPeer::handleDragExit, sender); }
static void mouseDown (id self, SEL s, NSEvent* ev)
@@ -2651,6 +2651,8 @@ private:
withObject: ev
waitUntilDone: NO];
}
+
+ __reflectionBasedSuperCall(self, s, ev);
}
static void mouseUp (id self, SEL s, NSEvent* ev)
@@ -2668,6 +2670,18 @@ private:
withObject: ev
waitUntilDone: NO];
}
+
+ __reflectionBasedSuperCall(self, s, ev);
+ }
+
+ static void __reflectionBasedSuperCall(id self, SEL s, NSEvent* ev)
+ {
+ struct objc_super mySuper;
+ mySuper.receiver = self;
+ mySuper.super_class = class_getSuperclass(object_getClass(self));
+
+ auto super_call = reinterpret_cast<void(*)(struct objc_super*, SEL, NSEvent*)>(objc_msgSendSuper);
+ super_call(&mySuper, s, ev);
}
static NSDragOperation draggingUpdated (id self, SEL, id<NSDraggingInfo> sender)
Disclaimer: this was generated by AI and it said, this would be safe to call on every mouseEvent and would not impact performance (I remembered reflections in Java to be relatively slow compared to “conventional” concepts). I did as much reading about this as possible, but it was difficult to find proper documentation and examples.
In addition: this does not work when clicking on the windows title.
