// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/theme_helper_mac.h" #import #include "base/command_line.h" #include "base/mac/mac_util.h" #include "base/mac/sdk_forward_declarations.h" #include "base/strings/sys_string_conversions.h" #include "content/common/view_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_switches.h" using content::RenderProcessHost; using content::ThemeHelperMac; namespace { bool GetScrollAnimationEnabled() { bool enabled = false; id value = nil; if (base::mac::IsOSMountainLionOrLater()) { value = [[NSUserDefaults standardUserDefaults] objectForKey:@"NSScrollAnimationEnabled"]; } else { value = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollAnimationEnabled"]; } if (value) enabled = [value boolValue]; return enabled; } blink::ScrollbarButtonsPlacement GetButtonPlacement() { NSString* scrollbar_variant = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; if ([scrollbar_variant isEqualToString:@"Single"]) return blink::ScrollbarButtonsPlacementSingle; else if ([scrollbar_variant isEqualToString:@"DoubleMin"]) return blink::ScrollbarButtonsPlacementDoubleStart; else if ([scrollbar_variant isEqualToString:@"DoubleBoth"]) return blink::ScrollbarButtonsPlacementDoubleBoth; else return blink::ScrollbarButtonsPlacementDoubleEnd; } void FillScrollbarThemeParams(ViewMsg_UpdateScrollbarTheme_Params* params) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults synchronize]; params->initial_button_delay = [defaults floatForKey:@"NSScrollerButtonDelay"]; params->autoscroll_button_delay = [defaults floatForKey:@"NSScrollerButtonPeriod"]; params->jump_on_track_click = [defaults boolForKey:@"AppleScrollerPagingBehavior"]; params->preferred_scroller_style = ThemeHelperMac::GetPreferredScrollerStyle(); params->scroll_animation_enabled = GetScrollAnimationEnabled(); params->button_placement = GetButtonPlacement(); } ViewMsg_SystemColorsChanged* CreateSystemColorsChangedMessage() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults synchronize]; return new ViewMsg_SystemColorsChanged( [[defaults stringForKey:@"AppleAquaColorVariant"] intValue], base::SysNSStringToUTF8( [defaults stringForKey:@"AppleHighlightedTextColor"]), base::SysNSStringToUTF8( [defaults stringForKey:@"AppleHighlightColor"])); } } // namespace @interface ScrollbarPrefsObserver : NSObject + (void)registerAsObserver; + (void)appearancePrefsChanged:(NSNotification*)notification; + (void)behaviorPrefsChanged:(NSNotification*)notification; + (void)notifyPrefsChangedWithRedraw:(BOOL)redraw; @end @implementation ScrollbarPrefsObserver + (void)registerAsObserver { NSDistributedNotificationCenter* distributedCenter = [NSDistributedNotificationCenter defaultCenter]; [distributedCenter addObserver:self selector:@selector(appearancePrefsChanged:) name:@"AppleAquaScrollBarVariantChanged" object:nil suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately]; [distributedCenter addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"AppleNoRedisplayAppearancePreferenceChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce]; if (base::mac::IsOSMountainLionOrLater()) { [distributedCenter addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"NSScrollAnimationEnabled" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce]; } else { // Register for < 10.8 [distributedCenter addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"AppleScrollAnimationEnabled" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce]; } [distributedCenter addObserver:self selector:@selector(appearancePrefsChanged:) name:@"AppleScrollBarVariant" object:nil suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately]; // In single-process mode, renderers will catch these notifications // themselves and listening for them here may trigger the DCHECK in Observe(). if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kSingleProcess)) { NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; if ([NSScroller respondsToSelector:@selector(preferredScrollerStyle)]) { [center addObserver:self selector:@selector(behaviorPrefsChanged:) name:NSPreferredScrollerStyleDidChangeNotification object:nil]; } [center addObserver:self selector:@selector(systemColorsChanged:) name:NSSystemColorsDidChangeNotification object:nil]; } } + (void)appearancePrefsChanged:(NSNotification*)notification { [self notifyPrefsChangedWithRedraw:YES]; } + (void)behaviorPrefsChanged:(NSNotification*)notification { [self notifyPrefsChangedWithRedraw:NO]; } + (void)systemColorsChanged:(NSNotification*)notification { for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); !it.IsAtEnd(); it.Advance()) { it.GetCurrentValue()->Send(CreateSystemColorsChangedMessage()); } } + (void)notifyPrefsChangedWithRedraw:(BOOL)redraw { ViewMsg_UpdateScrollbarTheme_Params params; FillScrollbarThemeParams(¶ms); params.redraw = redraw; for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); !it.IsAtEnd(); it.Advance()) { it.GetCurrentValue()->Send(new ViewMsg_UpdateScrollbarTheme(params)); } } @end namespace content { // static ThemeHelperMac* ThemeHelperMac::GetInstance() { return base::Singleton>::get(); } // static blink::ScrollerStyle ThemeHelperMac::GetPreferredScrollerStyle() { if (![NSScroller respondsToSelector:@selector(preferredScrollerStyle)]) return blink::ScrollerStyleLegacy; return static_cast([NSScroller preferredScrollerStyle]); } ThemeHelperMac::ThemeHelperMac() { [ScrollbarPrefsObserver registerAsObserver]; registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CREATED, NotificationService::AllSources()); } ThemeHelperMac::~ThemeHelperMac() { } void ThemeHelperMac::Observe(int type, const NotificationSource& source, const NotificationDetails& details) { DCHECK_EQ(NOTIFICATION_RENDERER_PROCESS_CREATED, type); // When a new RenderProcess is created, send it the initial preference // parameters. ViewMsg_UpdateScrollbarTheme_Params params; FillScrollbarThemeParams(¶ms); params.redraw = false; RenderProcessHost* rph = Source(source).ptr(); rph->Send(new ViewMsg_UpdateScrollbarTheme(params)); rph->Send(CreateSystemColorsChangedMessage()); } } // namespace content