Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import <Cocoa/Cocoa.h> | 5 #import <Cocoa/Cocoa.h> |
| 6 | 6 |
| 7 #import "remoting/host/disconnect_window_mac.h" | 7 #include "chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa.h" |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/i18n/rtl.h" | |
| 11 #include "base/mac/bundle_locations.h" | |
| 10 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 11 #include "base/sys_string_conversions.h" | 13 #include "base/sys_string_conversions.h" |
| 12 #include "remoting/host/disconnect_window.h" | 14 #include "grit/generated_resources.h" |
| 13 #include "remoting/host/ui_strings.h" | 15 #include "ui/base/l10n/l10n_util.h" |
| 14 | 16 |
| 15 @interface DisconnectWindowController() | 17 @interface ScreenCaptureNotificationController() |
| 16 - (BOOL)isRToL; | |
| 17 - (void)Hide; | 18 - (void)Hide; |
| 18 @end | 19 @end |
| 19 | 20 |
| 20 namespace remoting { | 21 class ScreenCaptureNotificationUICocoa : public ScreenCaptureNotificationUI { |
| 22 public: | |
| 23 ScreenCaptureNotificationUICocoa(); | |
| 24 virtual ~ScreenCaptureNotificationUICocoa(); | |
| 21 | 25 |
| 22 class DisconnectWindowMac : public remoting::DisconnectWindow { | 26 // ScreenCaptureNotificationUI interface. |
| 23 public: | 27 virtual bool Show(const base::Closure& stop_callback, |
| 24 explicit DisconnectWindowMac(const UiStrings* ui_strings); | 28 const string16& title) OVERRIDE; |
| 25 virtual ~DisconnectWindowMac(); | |
| 26 | |
| 27 virtual bool Show(const base::Closure& disconnect_callback, | |
| 28 const std::string& username) OVERRIDE; | |
| 29 virtual void Hide() OVERRIDE; | |
| 30 | 29 |
| 31 private: | 30 private: |
| 32 DisconnectWindowController* window_controller_; | 31 ScreenCaptureNotificationController* window_controller_; |
| 33 | 32 |
| 34 // Points to the localized strings. | 33 DISALLOW_COPY_AND_ASSIGN(ScreenCaptureNotificationUICocoa); |
| 35 const UiStrings* ui_strings_; | |
| 36 | |
| 37 DISALLOW_COPY_AND_ASSIGN(DisconnectWindowMac); | |
| 38 }; | 34 }; |
| 39 | 35 |
| 40 DisconnectWindowMac::DisconnectWindowMac(const UiStrings* ui_strings) | 36 ScreenCaptureNotificationUICocoa::ScreenCaptureNotificationUICocoa() |
| 41 : window_controller_(nil), | 37 : window_controller_(nil) { |
| 42 ui_strings_(ui_strings) { | |
| 43 } | 38 } |
| 44 | 39 |
| 45 DisconnectWindowMac::~DisconnectWindowMac() { | 40 ScreenCaptureNotificationUICocoa::~ScreenCaptureNotificationUICocoa() { |
| 46 Hide(); | 41 // ScreenCaptureNotificationController is responsible for releasing itself in |
| 42 // its windowWillClose: method. | |
| 43 [window_controller_ Hide]; | |
| 44 window_controller_ = nil; | |
| 47 } | 45 } |
| 48 | 46 |
| 49 bool DisconnectWindowMac::Show(const base::Closure& disconnect_callback, | 47 bool ScreenCaptureNotificationUICocoa::Show(const base::Closure& stop_callback, |
| 50 const std::string& username) { | 48 const string16& title) { |
| 51 DCHECK(!disconnect_callback.is_null()); | 49 DCHECK(!stop_callback.is_null()); |
| 52 DCHECK(window_controller_ == nil); | 50 DCHECK(window_controller_ == nil); |
| 53 | 51 |
| 54 window_controller_ = | 52 window_controller_ = |
| 55 [[DisconnectWindowController alloc] initWithUiStrings:ui_strings_ | 53 [[ScreenCaptureNotificationController alloc] |
| 56 callback:disconnect_callback | 54 initWithCallback:stop_callback |
| 57 username:username]; | 55 title:title]; |
| 58 [window_controller_ showWindow:nil]; | 56 [window_controller_ showWindow:nil]; |
| 59 return true; | 57 return true; |
| 60 } | 58 } |
| 61 | 59 |
| 62 void DisconnectWindowMac::Hide() { | 60 scoped_ptr<ScreenCaptureNotificationUI> ScreenCaptureNotificationUI::Create() { |
| 63 // DisconnectWindowController is responsible for releasing itself in its | 61 return scoped_ptr<ScreenCaptureNotificationUI>( |
| 64 // windowWillClose: method. | 62 new ScreenCaptureNotificationUICocoa()); |
| 65 [window_controller_ Hide]; | |
| 66 window_controller_ = nil; | |
| 67 } | 63 } |
| 68 | 64 |
| 69 scoped_ptr<DisconnectWindow> DisconnectWindow::Create( | 65 @implementation ScreenCaptureNotificationController |
| 70 const UiStrings* ui_strings) { | 66 - (id)initWithCallback:(const base::Closure&)stop_callback |
| 71 return scoped_ptr<DisconnectWindow>(new DisconnectWindowMac(ui_strings)); | 67 title:(const string16&)title { |
| 72 } | 68 NSString* nibpath = |
| 73 | 69 [base::mac::FrameworkBundle() pathForResource:@"ScreenCaptureNotification" |
| 74 } // namespace remoting | 70 ofType:@"nib"]; |
| 75 | 71 self = [super initWithWindowNibPath:nibpath owner:self]; |
| 76 @implementation DisconnectWindowController | |
| 77 - (id)initWithUiStrings:(const remoting::UiStrings*)ui_strings | |
| 78 callback:(const base::Closure&)disconnect_callback | |
| 79 username:(const std::string&)username { | |
| 80 self = [super initWithWindowNibName:@"disconnect_window"]; | |
| 81 if (self) { | 72 if (self) { |
| 82 ui_strings_ = ui_strings; | 73 stop_callback_ = stop_callback; |
| 83 disconnect_callback_ = disconnect_callback; | 74 title_ = title; |
| 84 username_ = UTF8ToUTF16(username); | |
| 85 } | 75 } |
| 86 return self; | 76 return self; |
| 87 } | 77 } |
| 88 | 78 |
| 89 - (void)dealloc { | 79 - (void)dealloc { |
| 90 [super dealloc]; | 80 [super dealloc]; |
| 91 } | 81 } |
| 92 | 82 |
| 93 - (IBAction)stopSharing:(id)sender { | 83 - (IBAction)stopSharing:(id)sender { |
| 94 if (!disconnect_callback_.is_null()) { | 84 if (!stop_callback_.is_null()) { |
| 95 disconnect_callback_.Run(); | 85 stop_callback_.Run(); |
| 96 } | 86 } |
| 97 } | 87 } |
| 98 | 88 |
| 99 - (BOOL)isRToL { | |
| 100 return ui_strings_->direction == remoting::UiStrings::RTL; | |
| 101 } | |
| 102 | |
| 103 - (void)Hide { | 89 - (void)Hide { |
| 104 disconnect_callback_.Reset(); | 90 stop_callback_.Reset(); |
| 105 [self close]; | 91 [self close]; |
| 106 } | 92 } |
| 107 | 93 |
| 108 - (void)windowDidLoad { | 94 - (void)windowDidLoad { |
| 109 string16 text = ReplaceStringPlaceholders(ui_strings_->disconnect_message, | 95 string16 text = l10n_util::GetStringFUTF16( |
| 110 username_, NULL); | 96 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, title_); |
| 111 [connectedToField_ setStringValue:base::SysUTF16ToNSString(text)]; | 97 [statusField_ setStringValue:base::SysUTF16ToNSString(text)]; |
| 112 | 98 |
| 113 [disconnectButton_ setTitle:base::SysUTF16ToNSString( | 99 string16 button_label = |
| 114 ui_strings_->disconnect_button_text)]; | 100 l10n_util::GetStringUTF16(IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP); |
| 101 [stopButton_ setTitle:base::SysUTF16ToNSString(button_label)]; | |
| 115 | 102 |
| 116 // Resize the window dynamically based on the content. | 103 // Resize the window dynamically based on the content. |
| 117 CGFloat oldConnectedWidth = NSWidth([connectedToField_ bounds]); | 104 CGFloat oldConnectedWidth = NSWidth([statusField_ bounds]); |
| 118 [connectedToField_ sizeToFit]; | 105 [statusField_ sizeToFit]; |
| 119 NSRect connectedToFrame = [connectedToField_ frame]; | 106 NSRect statusFrame = [statusField_ frame]; |
| 120 CGFloat newConnectedWidth = NSWidth(connectedToFrame); | 107 CGFloat newConnectedWidth = NSWidth(statusFrame); |
| 121 | 108 |
| 122 // Set a max width for the connected to text field. | 109 // Set a max width for the connected to text field. |
| 123 if (newConnectedWidth > | 110 const int kMaximumStatusWidth = 400; |
| 124 remoting::DisconnectWindow::kMaximumConnectedNameWidthInPixels) { | 111 if (newConnectedWidth > kMaximumStatusWidth) { |
| 125 newConnectedWidth | 112 newConnectedWidth = kMaximumStatusWidth; |
| 126 = remoting::DisconnectWindow::kMaximumConnectedNameWidthInPixels; | 113 statusFrame.size.width = newConnectedWidth; |
| 127 connectedToFrame.size.width = newConnectedWidth; | 114 [statusField_ setFrame:statusFrame]; |
| 128 [connectedToField_ setFrame:connectedToFrame]; | |
| 129 } | 115 } |
| 130 | 116 |
| 131 CGFloat oldDisconnectWidth = NSWidth([disconnectButton_ bounds]); | 117 CGFloat oldstopWidth = NSWidth([stopButton_ bounds]); |
| 132 [disconnectButton_ sizeToFit]; | 118 [stopButton_ sizeToFit]; |
| 133 NSRect disconnectFrame = [disconnectButton_ frame]; | 119 NSRect stopFrame = [stopButton_ frame]; |
| 134 CGFloat newDisconnectWidth = NSWidth(disconnectFrame); | 120 CGFloat newStopWidth = NSWidth(stopFrame); |
| 135 | 121 |
| 136 // Move the disconnect button appropriately. | 122 // Move the stop button appropriately. |
| 137 disconnectFrame.origin.x += newConnectedWidth - oldConnectedWidth; | 123 stopFrame.origin.x += newConnectedWidth - oldConnectedWidth; |
| 138 [disconnectButton_ setFrame:disconnectFrame]; | 124 [stopButton_ setFrame:stopFrame]; |
| 139 | 125 |
| 140 // Then resize the window appropriately | 126 // Then resize the window appropriately |
|
Nico
2013/03/22 18:46:37
.
Sergey Ulanov
2013/03/22 19:39:09
Done.
| |
| 141 NSWindow *window = [self window]; | 127 NSWindow *window = [self window]; |
| 142 NSRect windowFrame = [window frame]; | 128 NSRect windowFrame = [window frame]; |
| 143 windowFrame.size.width += (newConnectedWidth - oldConnectedWidth + | 129 windowFrame.size.width += (newConnectedWidth - oldConnectedWidth + |
| 144 newDisconnectWidth - oldDisconnectWidth); | 130 newStopWidth - oldstopWidth); |
| 145 [window setFrame:windowFrame display:NO]; | 131 [window setFrame:windowFrame display:NO]; |
| 146 | 132 |
| 147 if ([self isRToL]) { | 133 if (base::i18n::IsRTL()) { |
| 148 // Handle right to left case | 134 // Handle right to left case |
| 149 CGFloat buttonInset = NSWidth(windowFrame) - NSMaxX(disconnectFrame); | 135 CGFloat buttonInset = NSWidth(windowFrame) - NSMaxX(stopFrame); |
| 150 CGFloat buttonTextSpacing | 136 CGFloat buttonTextSpacing |
| 151 = NSMinX(disconnectFrame) - NSMaxX(connectedToFrame); | 137 = NSMinX(stopFrame) - NSMaxX(statusFrame); |
| 152 disconnectFrame.origin.x = buttonInset; | 138 stopFrame.origin.x = buttonInset; |
| 153 connectedToFrame.origin.x = NSMaxX(disconnectFrame) + buttonTextSpacing; | 139 statusFrame.origin.x = NSMaxX(stopFrame) + buttonTextSpacing; |
| 154 [connectedToField_ setFrame:connectedToFrame]; | 140 [statusField_ setFrame:statusFrame]; |
| 155 [disconnectButton_ setFrame:disconnectFrame]; | 141 [stopButton_ setFrame:stopFrame]; |
| 156 } | 142 } |
| 157 | 143 |
| 158 // Center the window at the bottom of the screen, above the dock (if present). | 144 // Center the window at the bottom of the screen, above the dock (if present). |
| 159 NSRect desktopRect = [[NSScreen mainScreen] visibleFrame]; | 145 NSRect desktopRect = [[NSScreen mainScreen] visibleFrame]; |
| 160 NSRect windowRect = [[self window] frame]; | 146 NSRect windowRect = [[self window] frame]; |
| 161 CGFloat x = (NSWidth(desktopRect) - NSWidth(windowRect)) / 2; | 147 CGFloat x = (NSWidth(desktopRect) - NSWidth(windowRect)) / 2; |
| 162 CGFloat y = NSMinY(desktopRect); | 148 CGFloat y = NSMinY(desktopRect); |
| 163 [[self window] setFrameOrigin:NSMakePoint(x, y)]; | 149 [[self window] setFrameOrigin:NSMakePoint(x, y)]; |
| 164 } | 150 } |
| 165 | 151 |
| 166 - (void)windowWillClose:(NSNotification*)notification { | 152 - (void)windowWillClose:(NSNotification*)notification { |
| 167 [self stopSharing:self]; | 153 [self stopSharing:self]; |
| 168 [self autorelease]; | 154 [self autorelease]; |
| 169 } | 155 } |
| 170 | 156 |
| 171 @end | 157 @end |
| 172 | 158 |
| 173 | 159 |
| 174 @interface DisconnectWindow() | 160 @implementation ScreenCaptureNotificationWindow |
| 175 - (BOOL)isRToL; | |
| 176 @end | |
| 177 | |
| 178 @implementation DisconnectWindow | |
| 179 | |
| 180 - (id)initWithContentRect:(NSRect)contentRect | 161 - (id)initWithContentRect:(NSRect)contentRect |
| 181 styleMask:(NSUInteger)aStyle | 162 styleMask:(NSUInteger)aStyle |
| 182 backing:(NSBackingStoreType)bufferingType | 163 backing:(NSBackingStoreType)bufferingType |
| 183 defer:(BOOL)flag { | 164 defer:(BOOL)flag { |
| 184 // Pass NSBorderlessWindowMask for the styleMask to remove the title bar. | 165 // Pass NSBorderlessWindowMask for the styleMask to remove the title bar. |
| 185 self = [super initWithContentRect:contentRect | 166 self = [super initWithContentRect:contentRect |
| 186 styleMask:NSBorderlessWindowMask | 167 styleMask:NSBorderlessWindowMask |
| 187 backing:bufferingType | 168 backing:bufferingType |
| 188 defer:flag]; | 169 defer:flag]; |
| 189 | 170 |
| 190 if (self) { | 171 if (self) { |
| 191 // Set window to be clear and non-opaque so we can see through it. | 172 // Set window to be clear and non-opaque so we can see through it. |
| 192 [self setBackgroundColor:[NSColor clearColor]]; | 173 [self setBackgroundColor:[NSColor clearColor]]; |
| 193 [self setOpaque:NO]; | 174 [self setOpaque:NO]; |
| 194 [self setMovableByWindowBackground:YES]; | 175 [self setMovableByWindowBackground:YES]; |
| 195 | 176 |
| 196 // Pull the window up to Status Level so that it always displays. | 177 // Pull the window up to Status Level so that it always displays. |
| 197 [self setLevel:NSStatusWindowLevel]; | 178 [self setLevel:NSStatusWindowLevel]; |
| 198 } | 179 } |
| 199 return self; | 180 return self; |
| 200 } | 181 } |
| 201 | |
| 202 - (BOOL)isRToL { | |
| 203 DCHECK([[self windowController] respondsToSelector:@selector(isRToL)]); | |
| 204 return [[self windowController] isRToL]; | |
| 205 } | |
| 206 | |
| 207 @end | 182 @end |
| 208 | 183 |
| 209 | 184 @implementation ScreenCaptureNotificationView |
| 210 @interface DisconnectView() | |
| 211 - (BOOL)isRToL; | |
| 212 @end | |
| 213 | |
| 214 @implementation DisconnectView | |
| 215 | |
| 216 - (BOOL)isRToL { | |
| 217 DCHECK([[self window] isKindOfClass:[DisconnectWindow class]]); | |
| 218 return [static_cast<DisconnectWindow*>([self window]) isRToL]; | |
| 219 } | |
| 220 | |
| 221 - (void)drawRect:(NSRect)rect { | 185 - (void)drawRect:(NSRect)rect { |
| 222 // All magic numbers taken from screen shots provided by UX. | 186 // All magic numbers taken from screen shots provided by UX. |
| 223 NSRect bounds = NSInsetRect([self bounds], 1, 1); | 187 NSRect bounds = NSInsetRect([self bounds], 1, 1); |
| 224 | 188 |
| 225 NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:bounds | 189 NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:bounds |
| 226 xRadius:5 | 190 xRadius:5 |
| 227 yRadius:5]; | 191 yRadius:5]; |
| 228 NSColor *gray = [NSColor colorWithCalibratedWhite:0.91 alpha:1.0]; | 192 NSColor *gray = [NSColor colorWithCalibratedWhite:0.91 alpha:1.0]; |
| 229 [gray setFill]; | 193 [gray setFill]; |
| 230 [path fill]; | 194 [path fill]; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 241 const CGFloat kHeight = 21.0; | 205 const CGFloat kHeight = 21.0; |
| 242 const CGFloat kBaseInset = 12.0; | 206 const CGFloat kBaseInset = 12.0; |
| 243 const CGFloat kDragHandleWidth = 5.0; | 207 const CGFloat kDragHandleWidth = 5.0; |
| 244 | 208 |
| 245 NSColor *dark = [NSColor colorWithCalibratedWhite:0.70 alpha:1.0]; | 209 NSColor *dark = [NSColor colorWithCalibratedWhite:0.70 alpha:1.0]; |
| 246 NSColor *light = [NSColor colorWithCalibratedWhite:0.97 alpha:1.0]; | 210 NSColor *light = [NSColor colorWithCalibratedWhite:0.97 alpha:1.0]; |
| 247 | 211 |
| 248 // Turn off aliasing so it's nice and crisp. | 212 // Turn off aliasing so it's nice and crisp. |
| 249 NSGraphicsContext *context = [NSGraphicsContext currentContext]; | 213 NSGraphicsContext *context = [NSGraphicsContext currentContext]; |
| 250 BOOL alias = [context shouldAntialias]; | 214 BOOL alias = [context shouldAntialias]; |
| 251 [context setShouldAntialias:NO]; | 215 [context setShouldAntialias:NO]; |
|
Nico
2013/03/22 18:46:37
Can you upload a screenshot for this please?
Anti
Sergey Ulanov
2013/03/22 19:39:09
Here is a screenshot from mac: http://i.imgur.com/
| |
| 252 | 216 |
| 253 // Handle bidirectional locales properly. | 217 // Handle bidirectional locales properly. |
|
Nico
2013/03/22 18:46:37
Chrome/Mac doesn't handle RTL as far as I know. (m
| |
| 254 CGFloat inset = [self isRToL] ? NSMaxX(bounds) - kBaseInset - kDragHandleWidth | 218 CGFloat inset = base::i18n::IsRTL() ? |
| 255 : kBaseInset; | 219 NSMaxX(bounds) - kBaseInset - kDragHandleWidth : kBaseInset; |
| 256 | 220 |
| 257 NSPoint top = NSMakePoint(inset, NSMidY(bounds) - kHeight / 2.0); | 221 NSPoint top = NSMakePoint(inset, NSMidY(bounds) - kHeight / 2.0); |
| 258 NSPoint bottom = NSMakePoint(inset, top.y + kHeight); | 222 NSPoint bottom = NSMakePoint(inset, top.y + kHeight); |
| 259 | 223 |
| 260 path = [NSBezierPath bezierPath]; | 224 path = [NSBezierPath bezierPath]; |
| 261 [path moveToPoint:top]; | 225 [path moveToPoint:top]; |
| 262 [path lineToPoint:bottom]; | 226 [path lineToPoint:bottom]; |
| 263 [dark setStroke]; | 227 [dark setStroke]; |
| 264 [path stroke]; | 228 [path stroke]; |
| 265 | 229 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 284 path = [NSBezierPath bezierPath]; | 248 path = [NSBezierPath bezierPath]; |
| 285 [path moveToPoint:top]; | 249 [path moveToPoint:top]; |
| 286 [path lineToPoint:bottom]; | 250 [path lineToPoint:bottom]; |
| 287 [light setStroke]; | 251 [light setStroke]; |
| 288 [path stroke]; | 252 [path stroke]; |
| 289 | 253 |
| 290 [context setShouldAntialias:alias]; | 254 [context setShouldAntialias:alias]; |
| 291 } | 255 } |
| 292 | 256 |
| 293 @end | 257 @end |
| OLD | NEW |