From 976d45a7ac55993e1fa6ef974e664b1896ae7580 Mon Sep 17 00:00:00 2001 From: JeffryBooher Date: Wed, 30 Oct 2013 14:47:02 -0700 Subject: [PATCH 1/3] fixes dark shell on mac going full screen --- appshell/cefclient_mac.mm | 5 ++++- appshell/client_handler_mac.mm | 10 ++++++++++ appshell/config.h | 4 ---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index 5418261c7..171a8a8c1 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -291,8 +291,9 @@ - (void)addCustomDrawHook:(NSView*)contentView - (void)removeCustomDrawHook:(NSView*)contentView { NSView* themeView = [contentView superview]; + Class NSThemeFrame = NSClassFromString(@"NSThemeFrame"); - object_setClass(themeView, NULL); + object_setClass(themeView, NSThemeFrame); } -(void)windowTitleDidChange:(NSString*)title { @@ -304,6 +305,8 @@ -(void)windowTitleDidChange:(NSString*)title { - (void)windowWillEnterFullScreen:(NSNotification *)notification { #ifdef DARK_UI NSWindow* window = [notification object]; + NSView* contentView = [window contentView]; + [self removeCustomDrawHook: contentView]; savedTitle = [[window title] copy]; [window setTitle:@""]; #endif diff --git a/appshell/client_handler_mac.mm b/appshell/client_handler_mac.mm index 816ed883a..463f4be21 100644 --- a/appshell/client_handler_mac.mm +++ b/appshell/client_handler_mac.mm @@ -223,6 +223,14 @@ - (void)addCustomDrawHook:(NSView*)contentView #endif } +- (void)removeCustomDrawHook:(NSView*)contentView +{ + NSView* themeView = [contentView superview]; + Class NSThemeFrame = NSClassFromString(@"NSThemeFrame"); + + object_setClass(themeView, NSThemeFrame); +} + - (IBAction)handleMenuAction:(id)sender { if (clientHandler.get() && clientHandler->GetBrowserId()) { CefRefPtr browser = ClientHandler::GetBrowserForNativeWindow(window); @@ -276,6 +284,8 @@ -(void)windowTitleDidChange:(NSString*)title { - (void)windowWillEnterFullScreen:(NSNotification *)notification { #ifdef DARK_UI + NSView* contentView = [window contentView]; + [self removeCustomDrawHook: contentView]; savedTitle = [[window title] copy]; [window setTitle:@""]; #endif diff --git a/appshell/config.h b/appshell/config.h index a5b4e6817..c1331bd7e 100644 --- a/appshell/config.h +++ b/appshell/config.h @@ -63,11 +63,7 @@ #define REMOTE_DEBUGGING_PORT 9234 -#ifdef OS_WIN - // Comment out this line to enable OS themed drawing #define DARK_UI #define CUSTOM_TRAFFIC_LIGHTS #define LIGHT_CAPTION_TEXT - -#endif From bc51315e01af9907c28a7e268688a55c11d9a9ff Mon Sep 17 00:00:00 2001 From: Bob Easterday Date: Fri, 8 Nov 2013 16:14:53 -0800 Subject: [PATCH 2/3] First pass at creating a custom title bar without swizzling --- appshell/CustomTitlebarView.h | 18 ++++ appshell/CustomTitlebarView.m | 88 ++++++++++++++++ appshell/cefclient_mac.mm | 193 +++++++++------------------------- appshell_paths.gypi | 4 + 4 files changed, 159 insertions(+), 144 deletions(-) create mode 100644 appshell/CustomTitlebarView.h create mode 100644 appshell/CustomTitlebarView.m diff --git a/appshell/CustomTitlebarView.h b/appshell/CustomTitlebarView.h new file mode 100644 index 000000000..751c37589 --- /dev/null +++ b/appshell/CustomTitlebarView.h @@ -0,0 +1,18 @@ +// +// CustomTitlebarView.h +// appshell +// +// Created by Bob Easterday on 11/6/13. +// +// + +#import + +@interface CustomTitlebarView : NSView +{ + NSString *titleString; +} + +@property (nonatomic, strong) NSString *titleString; + +@end diff --git a/appshell/CustomTitlebarView.m b/appshell/CustomTitlebarView.m new file mode 100644 index 000000000..2905e01c5 --- /dev/null +++ b/appshell/CustomTitlebarView.m @@ -0,0 +1,88 @@ +// +// CustomTitlebarView.m +// appshell +// +// Created by Bob Easterday on 11/6/13. +// +// + +#import "CustomTitlebarView.h" +#import "client_colors_mac.h" + +#define titleTextHeight 16 + +@implementation CustomTitlebarView + +@synthesize titleString; + +- (void)drawRect:(NSRect)dirtyRect +{ + NSColorSpace *sRGB = [NSColorSpace sRGBColorSpace]; + NSRect windowFrame = [NSWindow frameRectForContentRect:[[[self window] contentView] bounds] styleMask:[[self window] styleMask]]; + NSRect contentBounds = [[[self window] contentView] bounds]; + + NSRect titlebarRect = NSMakeRect(0, 0, self.bounds.size.width, windowFrame.size.height - contentBounds.size.height); + titlebarRect.origin.y = self.bounds.size.height - titlebarRect.size.height; + + [[NSColor clearColor] set]; + NSRectFill( titlebarRect ); + + //This constant matches the radius for other macosx apps. + //For some reason if we use the default value it is double that of safari etc. + float cornerRadius = 4.0f; + + [[NSBezierPath bezierPathWithRoundedRect:titlebarRect + xRadius:cornerRadius + yRadius:cornerRadius] addClip]; + [[NSBezierPath bezierPathWithRect:titlebarRect] addClip]; + + NSColor *fillColor = [NSColor colorWithColorSpace:sRGB components:fillComp count:4]; + [fillColor set]; + NSRectFill(titlebarRect); + + NSFont *titleFont = [NSFont fontWithName:@"HelveticaNeue-Bold" size:titleTextHeight]; + CGFloat stringWidth = [self widthOfString:titleString withFont:titleFont]; + NSColor *activeColor = [NSColor colorWithColorSpace:sRGB components:activeComp count:4]; + NSColor *inactiveColor = [NSColor colorWithColorSpace:sRGB components:inactiveComp count:4]; + + if (stringWidth) + { + NSRect textRect = NSMakeRect(titlebarRect.origin.x + ((titlebarRect.size.width / 2) - (stringWidth / 2)), + titlebarRect.origin.y + ((titlebarRect.size.height / 2) - (titleTextHeight / 2)), + titlebarRect.size.width, + titlebarRect.size.height); + + [titleString drawInRect:textRect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys: + titleFont, NSFontAttributeName, + [NSApp isActive] ? activeColor : inactiveColor, + NSForegroundColorAttributeName, + nil]]; + } +} + +- (CGFloat)widthOfString:(NSString *)string withFont:(NSFont *)font +{ + if (string == nil || [string length] == 0) + return 0.0f; + + NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; + return [[[NSAttributedString alloc] initWithString:string attributes:attributes] size].width; +} + +#pragma mark Property accessors + +- (NSString *)titleString +{ + return titleString; +} + +- (void)setTitleString:(NSString *)aString +{ + if ((!titleString && !aString) || (titleString && aString && [titleString isEqualToString:aString])) + return; + titleString = [aString copy]; + [self setNeedsDisplay:YES]; +} + + +@end diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index 171a8a8c1..3fef549b3 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -30,6 +30,7 @@ #include "FullScreenView.h" #include "FullScreenViewController.h" +#import "CustomTitlebarView.h" // Application startup time CFTimeInterval g_appStartupTime; @@ -107,6 +108,7 @@ - (NSWindow *) findTargetWindow { @end +// BOBNOTE: Consider moving the delegate interface into its own .h file @interface ClientMenuDelegate : NSObject { } - (void)menuWillOpen:(NSMenu *)menu; @@ -126,87 +128,14 @@ - (void)menuWillOpen:(NSMenu *)menu { @end - - -// Custom draw interface for NSThemeFrame -@interface NSView (UndocumentedAPI) -- (float)roundedCornerRadius; -- (CGRect)_titlebarTitleRect; -- (NSTextFieldCell*)titleCell; -- (void)_drawTitleStringIn:(struct CGRect)arg1 withColor:(id)color; -@end - -/** - * The patched implementation for drawRect that lets us tweak - * the title bar. - */ -void ShellWindowFrameDrawRect(id self, SEL _cmd, NSRect rect) { - // Clear to 0 alpha - [[NSColor clearColor] set]; - NSRectFill( rect ); - //Obtain reference to our NSThemeFrame view - NSRect windowRect = [self frame]; - windowRect.origin = NSMakePoint(0,0); - //This constant matches the radius for other macosx apps. - //For some reason if we use the default value it is double that of safari etc. - float cornerRadius = 4.0f; - - //Clip our title bar render - [[NSBezierPath bezierPathWithRoundedRect:windowRect - xRadius:cornerRadius - yRadius:cornerRadius] addClip]; - [[NSBezierPath bezierPathWithRect:rect] addClip]; - - - - NSColorSpace *sRGB = [NSColorSpace sRGBColorSpace]; - NSColor *fillColor = [NSColor colorWithColorSpace:sRGB components:fillComp count:4]; - [fillColor set]; - NSRectFill( rect ); - NSColor *activeColor = [NSColor colorWithColorSpace:sRGB components:activeComp count:4]; - NSColor *inactiveColor = [NSColor colorWithColorSpace:sRGB components:inactiveComp count:4]; - // Render our title text - [self _drawTitleStringIn:[self _titlebarTitleRect] - withColor:[NSApp isActive] ? - activeColor : inactiveColor]; - - - - -} - - - - -/** - * Create a custom class based on NSThemeFrame called - * ShellWindowFrame. ShellWindowFrame uses ShellWindowFrameDrawRect() - * as the implementation for the drawRect selector allowing us - * to draw the border/title bar the way we see fit. - */ -Class GetShellWindowFrameClass() { - // lazily change the class implementation if - // not done so already. - static Class k = NULL; - if (!k) { - // See http://cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html - Class NSThemeFrame = NSClassFromString(@"NSThemeFrame"); - k = objc_allocateClassPair(NSThemeFrame, "ShellWindowFrame", 0); - Method m0 = class_getInstanceMethod(NSThemeFrame, @selector(drawRect:)); - class_addMethod(k, @selector(drawRect:), - (IMP)ShellWindowFrameDrawRect, method_getTypeEncoding(m0)); - objc_registerClassPair(k); - } - return k; -} - - +// BOBNOTE: Consider moving the delegate interface into its own .h file // Receives notifications from controls and the browser window. Will delete // itself when done. @interface ClientWindowDelegate : NSObject { - BOOL isReallyClosing; - NSString* savedTitle; - NSView* fullScreenButtonView; + BOOL isReallyClosing; + NSView* fullScreenButtonView; + BOOL isReentering; + CustomTitlebarView *customTitlebar; } - (void)setIsReallyClosing; - (IBAction)handleMenuAction:(id)sender; @@ -218,15 +147,15 @@ - (void)notifyConsoleMessage:(id)object; - (void)notifyDownloadComplete:(id)object; - (void)notifyDownloadError:(id)object; - (void)setFullScreenButtonView:(NSView*)view; -- (void)addCustomDrawHook:(NSView*)contentView; @end @implementation ClientWindowDelegate - (id) init { - [super init]; - savedTitle = nil; - isReallyClosing = false; - return self; + [super init]; + isReallyClosing = false; + isReentering = NO; + + return self; } - (void)setIsReallyClosing { @@ -275,40 +204,9 @@ - (void)setFullScreenButtonView:(NSView *)view { fullScreenButtonView = view; } -- (void)addCustomDrawHook:(NSView*)contentView -{ - NSView* themeView = [contentView superview]; - - object_setClass(themeView, GetShellWindowFrameClass()); - -#ifdef LIGHT_CAPTION_TEXT - // Reset our frame view text cell background style - NSTextFieldCell * cell = [themeView titleCell]; - [cell setBackgroundStyle:NSBackgroundStyleLight]; -#endif -} - -- (void)removeCustomDrawHook:(NSView*)contentView -{ - NSView* themeView = [contentView superview]; - Class NSThemeFrame = NSClassFromString(@"NSThemeFrame"); - - object_setClass(themeView, NSThemeFrame); -} - -(void)windowTitleDidChange:(NSString*)title { #ifdef DARK_UI - savedTitle = [title copy]; -#endif -} - -- (void)windowWillEnterFullScreen:(NSNotification *)notification { -#ifdef DARK_UI - NSWindow* window = [notification object]; - NSView* contentView = [window contentView]; - [self removeCustomDrawHook: contentView]; - savedTitle = [[window title] copy]; - [window setTitle:@""]; + [customTitlebar setTitleString:title]; #endif } @@ -318,12 +216,15 @@ - (BOOL)isFullScreenSupported { return (version >= 0x1070); } - -(void)windowDidResize:(NSNotification *)notification { + +// BOBNOTE: this should be moved into the CustomTitlebarView class #ifdef DARK_UI + NSWindow* window = [notification object]; + if ([self isFullScreenSupported]) { - NSWindow* window = [notification object]; + NSView* themeView = [[window contentView] superview]; NSRect parentFrame = [themeView frame]; @@ -333,21 +234,20 @@ -(void)windowDidResize:(NSNotification *)notification oldFrame.size.width, // width oldFrame.size.height); - [fullScreenButtonView setFrame:newFrame]; [themeView setNeedsDisplay:YES]; } #endif } +// BOBNOTE: Consider moving this into the customTitlebarView class in which case you won't need to +// repeat this work every time you exit full screen mode. - (void)windowDidExitFullScreen:(NSNotification *)notification { NSWindow* window = [notification object]; NSView* contentView = [window contentView]; - NSView* themeView = [[window contentView] superview]; + NSView* themeView = [contentView superview]; + #ifdef DARK_UI - [self addCustomDrawHook: contentView]; - [window setTitle:savedTitle]; - [savedTitle release]; [themeView setNeedsDisplay:YES]; #endif @@ -380,6 +280,7 @@ - (void)windowDidExitFullScreen:(NSNotification *)notification { #endif #ifdef DARK_UI + if ([self isFullScreenSupported]) { windowButton = [theWin standardWindowButton:NSWindowFullScreenButton]; [windowButton setHidden:YES]; @@ -439,6 +340,27 @@ - (void)notifyDownloadError:(id)object { } - (void)windowDidBecomeKey:(NSNotification*)notification { +#ifdef DARK_UI + if (!isReentering) + { + NSWindow *thisWindow = [notification object]; + NSView* contentView = [thisWindow contentView]; + NSRect bounds = [[contentView superview] bounds]; + + customTitlebar = [[CustomTitlebarView alloc] initWithFrame:bounds]; + + // BOBNOTE: should get the initial title from a resource or app name as opposed to hard-coding + [customTitlebar setTitleString:@"Brackets"]; + + [customTitlebar setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + [[contentView superview] addSubview:customTitlebar positioned:NSWindowBelow relativeTo:[[[contentView superview] subviews] objectAtIndex:0]]; + + NSButton *windowButton = [thisWindow standardWindowButton:NSWindowFullScreenButton]; + [windowButton setHidden:YES]; + isReentering = YES; + } +#endif + if (g_handler.get() && g_handler->GetBrowserId()) { // Give focus to the browser window. g_handler->GetBrowser()->GetHost()->SetFocus(true); @@ -495,14 +417,16 @@ - (void)cleanup:(id)window { @end +// BOBNOTE: Consider moving the AppDelegate interface into its own .h file // Receives notifications from the application. Will delete itself when done. @interface ClientAppDelegate : NSObject - (void)createApp:(id)object; -- (void)addCustomDrawHook:(NSView*)contentView; - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename; - (BOOL)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames; @end + +// BOBNOTE: Consider moving the AppDelegate implementation into its own .m file @implementation ClientAppDelegate - (id) init { @@ -567,6 +491,7 @@ - (void)createApp:(id)object { NSWindow* theWin = mainWnd; NSButton *windowButton; +// BOBNOTE: Consider moving this into the customTitlebarView class #ifdef CUSTOM_TRAFFIC_LIGHTS //hide buttons windowButton = [theWin standardWindowButton:NSWindowCloseButton]; @@ -612,13 +537,6 @@ - (void)createApp:(id)object { [mainWnd setReleasedWhenClosed:NO]; NSView* contentView = [mainWnd contentView]; -#ifdef DARK_UI - // Register our custom title bar rendering hook. - [self addCustomDrawHook:contentView]; - windowButton = [theWin standardWindowButton:NSWindowFullScreenButton]; - [windowButton setHidden:YES]; -#endif - // Create the handler. g_handler = new ClientHandler(); @@ -649,6 +567,7 @@ - (void)createApp:(id)object { NSView *themeView = [[mainWnd contentView] superview]; NSRect parentFrame = [themeView frame]; + // BOBNOTE: Consider moving this into the customTitlebarView class #ifdef CUSTOM_TRAFFIC_LIGHTS TrafficLightsViewController *tvController = [[TrafficLightsViewController alloc] init]; if ([NSBundle loadNibNamed: @"TrafficLights" owner: tvController]) @@ -727,20 +646,6 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theAp return NSTerminateNow; } - -- (void)addCustomDrawHook:(NSView*)contentView -{ - NSView* themeView = [contentView superview]; - - object_setClass(themeView, GetShellWindowFrameClass()); - -#ifdef LIGHT_CAPTION_TEXT - // Reset our frame view text cell background style - NSTextFieldCell * cell = [themeView titleCell]; - [cell setBackgroundStyle:NSBackgroundStyleLight]; -#endif -} - - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { if (!pendingOpenFiles) { ClientApplication * clientApp = (ClientApplication *)theApplication; diff --git a/appshell_paths.gypi b/appshell_paths.gypi index 17e3596b0..7d747d934 100755 --- a/appshell_paths.gypi +++ b/appshell_paths.gypi @@ -149,6 +149,8 @@ 'appshell/TrafficLightsView.mm', 'appshell/TrafficLightsViewController.h', 'appshell/TrafficLightsViewController.mm', + 'appshell/CustomTitlebarView.h', + 'appshell/CustomTitlebarView.m', 'appshell/FullScreenButton.h', 'appshell/FullScreenButton.mm', 'appshell/FullScreenView.h', @@ -177,6 +179,8 @@ 'appshell/TrafficLightsView.mm', 'appshell/TrafficLightsViewController.h', 'appshell/TrafficLightsViewController.mm', + 'appshell/CustomTitlebarView.h', + 'appshell/CustomTitlebarView.m', 'appshell/FullScreenButton.h', 'appshell/FullScreenButton.mm', 'appshell/FullScreenView.h', From c90f956b71aca97ee2b676f70fa3767f22fff9a1 Mon Sep 17 00:00:00 2001 From: Bob Easterday Date: Mon, 11 Nov 2013 13:02:14 -0800 Subject: [PATCH 3/3] Wait for the app to come alive before starting the cef runloop --- appshell/cefclient_mac.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index 3fef549b3..de8737185 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -789,9 +789,8 @@ int main(int argc, char* argv[]) { } // Create the application delegate and window. - [delegate performSelectorOnMainThread:@selector(createApp:) withObject:nil - waitUntilDone:NO]; - + [delegate performSelectorOnMainThread:@selector(createApp:) withObject:nil waitUntilDone:YES]; + // Run the application message loop. CefRunMessageLoop();