| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 #include "chrome/browser/cocoa/nsimage_cache.h" | 5 #include "chrome/browser/cocoa/nsimage_cache.h" |
| 6 #include "chrome/browser/cocoa/tab_controller.h" | 6 #include "chrome/browser/cocoa/tab_controller.h" |
| 7 #include "chrome/browser/cocoa/tab_view.h" | 7 #include "chrome/browser/cocoa/tab_view.h" |
| 8 #include "chrome/browser/cocoa/tab_window_controller.h" | 8 #include "chrome/browser/cocoa/tab_window_controller.h" |
| 9 | 9 |
| 10 | 10 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 // corners of the tab inset by height*2/3, so we inset by half of | 79 // corners of the tab inset by height*2/3, so we inset by half of |
| 80 // that here. This doesn't completely eliminate the overlap, but it | 80 // that here. This doesn't completely eliminate the overlap, but it |
| 81 // works well enough. | 81 // works well enough. |
| 82 NSRect hitRect = NSInsetRect(frame, frame.size.height / 3.0f, 0); | 82 NSRect hitRect = NSInsetRect(frame, frame.size.height / 3.0f, 0); |
| 83 if (![closeButton_ isHidden]) | 83 if (![closeButton_ isHidden]) |
| 84 if (NSPointInRect(viewPoint, [closeButton_ frame])) return closeButton_; | 84 if (NSPointInRect(viewPoint, [closeButton_ frame])) return closeButton_; |
| 85 if (NSPointInRect(aPoint, hitRect)) return self; | 85 if (NSPointInRect(aPoint, hitRect)) return self; |
| 86 return nil; | 86 return nil; |
| 87 } | 87 } |
| 88 | 88 |
| 89 // Returns |YES| if this tab can be torn away into a new window. |
| 90 - (BOOL)canBeDragged { |
| 91 NSWindowController *controller = [sourceWindow_ windowController]; |
| 92 if ([controller isKindOfClass:[TabWindowController class]]) { |
| 93 TabWindowController* realController = |
| 94 static_cast<TabWindowController*>(controller); |
| 95 return [realController isTabDraggable:self]; |
| 96 } |
| 97 return YES; |
| 98 } |
| 99 |
| 89 // Handle clicks and drags in this button. We get here because we have | 100 // Handle clicks and drags in this button. We get here because we have |
| 90 // overridden acceptsFirstMouse: and the click is within our bounds. | 101 // overridden acceptsFirstMouse: and the click is within our bounds. |
| 91 // TODO(pinkerton/alcor): This routine needs *a lot* of work to marry Cole's | 102 // TODO(pinkerton/alcor): This routine needs *a lot* of work to marry Cole's |
| 92 // ideas of dragging cocoa views between windows and how the Browser and | 103 // ideas of dragging cocoa views between windows and how the Browser and |
| 93 // TabStrip models want to manage tabs. | 104 // TabStrip models want to manage tabs. |
| 94 | 105 |
| 95 static const CGFloat kTearDistance = 36.0; | 106 static const CGFloat kTearDistance = 36.0; |
| 96 static const NSTimeInterval kTearDuration = 0.333; | 107 static const NSTimeInterval kTearDuration = 0.333; |
| 97 static const double kDragStartDistance = 3.0; | 108 static const double kDragStartDistance = 3.0; |
| 98 | 109 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 117 targetController_ = nil; | 128 targetController_ = nil; |
| 118 tabWasDragged_ = NO; | 129 tabWasDragged_ = NO; |
| 119 tearTime_ = 0.0; | 130 tearTime_ = 0.0; |
| 120 draggingWithinTabStrip_ = YES; | 131 draggingWithinTabStrip_ = YES; |
| 121 | 132 |
| 122 // We don't want to "tear off" a tab if there's only one in the window. Treat | 133 // We don't want to "tear off" a tab if there's only one in the window. Treat |
| 123 // it like we're dragging around a tab we've already detached. Note that | 134 // it like we're dragging around a tab we've already detached. Note that |
| 124 // unit tests might have |-numberOfTabs| reporting zero since the model | 135 // unit tests might have |-numberOfTabs| reporting zero since the model |
| 125 // won't be fully hooked up. We need to be prepared for that and not send | 136 // won't be fully hooked up. We need to be prepared for that and not send |
| 126 // them into the "magnetic" codepath. | 137 // them into the "magnetic" codepath. |
| 127 isTheOnlyTab_ = [sourceController_ numberOfTabs] <= 1; | 138 moveWindowOnDrag_ = |
| 139 [sourceController_ numberOfTabs] <= 1 || ![self canBeDragged]; |
| 128 | 140 |
| 129 dragOrigin_ = [NSEvent mouseLocation]; | 141 dragOrigin_ = [NSEvent mouseLocation]; |
| 130 | 142 |
| 131 // Because we move views between windows, we need to handle the event loop | 143 // Because we move views between windows, we need to handle the event loop |
| 132 // ourselves. Ideally we should use the standard event loop. | 144 // ourselves. Ideally we should use the standard event loop. |
| 133 while (1) { | 145 while (1) { |
| 134 theEvent = | 146 theEvent = |
| 135 [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask | 147 [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask |
| 136 untilDate:[NSDate distantFuture] | 148 untilDate:[NSDate distantFuture] |
| 137 inMode:NSDefaultRunLoopMode dequeue:YES]; | 149 inMode:NSDefaultRunLoopMode dequeue:YES]; |
| 138 NSPoint thisPoint = [NSEvent mouseLocation]; | 150 NSPoint thisPoint = [NSEvent mouseLocation]; |
| 139 | 151 |
| 140 NSEventType type = [theEvent type]; | 152 NSEventType type = [theEvent type]; |
| 141 if (type == NSLeftMouseDragged) { | 153 if (type == NSLeftMouseDragged) { |
| 142 [self mouseDragged:theEvent]; | 154 [self mouseDragged:theEvent]; |
| 143 } else { // Mouse Up | 155 } else { // Mouse Up |
| 144 [self mouseUp:theEvent]; | 156 [self mouseUp:theEvent]; |
| 145 break; | 157 break; |
| 146 } | 158 } |
| 147 } | 159 } |
| 148 } | 160 } |
| 149 | 161 |
| 150 - (void)mouseDragged:(NSEvent *)theEvent { | 162 - (void)mouseDragged:(NSEvent *)theEvent { |
| 163 // Special-case this to keep the logic below simpler. |
| 164 if (moveWindowOnDrag_) { |
| 165 NSPoint thisPoint = [NSEvent mouseLocation]; |
| 166 NSPoint origin = sourceWindowFrame_.origin; |
| 167 origin.x += (thisPoint.x - dragOrigin_.x); |
| 168 origin.y += (thisPoint.y - dragOrigin_.y); |
| 169 [sourceWindow_ setFrameOrigin:NSMakePoint(origin.x, origin.y)]; |
| 170 return; |
| 171 } |
| 172 |
| 151 // First, go through the magnetic drag cycle. We break out of this if | 173 // First, go through the magnetic drag cycle. We break out of this if |
| 152 // "stretchiness" ever exceeds the a set amount. | 174 // "stretchiness" ever exceeds a set amount. |
| 153 tabWasDragged_ = YES; | 175 tabWasDragged_ = YES; |
| 154 | 176 |
| 155 if (isTheOnlyTab_) draggingWithinTabStrip_ = NO; | |
| 156 if (draggingWithinTabStrip_) { | 177 if (draggingWithinTabStrip_) { |
| 157 NSRect frame = [self frame]; | 178 NSRect frame = [self frame]; |
| 158 NSPoint thisPoint = [NSEvent mouseLocation]; | 179 NSPoint thisPoint = [NSEvent mouseLocation]; |
| 159 CGFloat stretchiness = thisPoint.y - dragOrigin_.y; | 180 CGFloat stretchiness = thisPoint.y - dragOrigin_.y; |
| 160 stretchiness = copysign(sqrtf(fabs(stretchiness))/sqrtf(kTearDistance), | 181 stretchiness = copysign(sqrtf(fabs(stretchiness))/sqrtf(kTearDistance), |
| 161 stretchiness) / 2.0; | 182 stretchiness) / 2.0; |
| 162 CGFloat offset = thisPoint.x - dragOrigin_.x; | 183 CGFloat offset = thisPoint.x - dragOrigin_.x; |
| 163 if (fabsf(offset) > 100) stretchiness = 0; | 184 if (fabsf(offset) > 100) stretchiness = 0; |
| 164 [sourceController_ insertPlaceholderForTab:self | 185 [sourceController_ insertPlaceholderForTab:self |
| 165 frame:NSOffsetRect(sourceTabFrame_, | 186 frame:NSOffsetRect(sourceTabFrame_, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 183 // moving more than 3 pixels. | 204 // moving more than 3 pixels. |
| 184 NSDate* targetDwellDate = nil; // The date this target was first chosen | 205 NSDate* targetDwellDate = nil; // The date this target was first chosen |
| 185 NSMutableArray* targets = [NSMutableArray array]; | 206 NSMutableArray* targets = [NSMutableArray array]; |
| 186 | 207 |
| 187 NSPoint thisPoint = [NSEvent mouseLocation]; | 208 NSPoint thisPoint = [NSEvent mouseLocation]; |
| 188 | 209 |
| 189 // Find all the windows that could be a target. It has to be of the | 210 // Find all the windows that could be a target. It has to be of the |
| 190 // appropriate class, and visible (obviously). | 211 // appropriate class, and visible (obviously). |
| 191 if (![targets count]) { | 212 if (![targets count]) { |
| 192 for (NSWindow* window in [NSApp windows]) { | 213 for (NSWindow* window in [NSApp windows]) { |
| 193 if (window == sourceWindow_ && isTheOnlyTab_) continue; | |
| 194 if (window == dragWindow_) continue; | 214 if (window == dragWindow_) continue; |
| 195 if (![window isVisible]) continue; | 215 if (![window isVisible]) continue; |
| 196 NSWindowController *controller = [window windowController]; | 216 NSWindowController *controller = [window windowController]; |
| 197 if ([controller isKindOfClass:[TabWindowController class]]) { | 217 if ([controller isKindOfClass:[TabWindowController class]]) { |
| 198 TabWindowController* realController = | 218 TabWindowController* realController = |
| 199 static_cast<TabWindowController*>(controller); | 219 static_cast<TabWindowController*>(controller); |
| 200 if ([realController canReceiveFrom:sourceController_]) { | 220 if ([realController canReceiveFrom:sourceController_]) { |
| 201 [targets addObject:controller]; | 221 [targets addObject:controller]; |
| 202 } | 222 } |
| 203 } | 223 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 228 [targetController_ removePlaceholder]; | 248 [targetController_ removePlaceholder]; |
| 229 targetController_ = newTarget; | 249 targetController_ = newTarget; |
| 230 if (!newTarget) { | 250 if (!newTarget) { |
| 231 tearTime_ = [NSDate timeIntervalSinceReferenceDate]; | 251 tearTime_ = [NSDate timeIntervalSinceReferenceDate]; |
| 232 tearOrigin_ = [dragWindow_ frame].origin; | 252 tearOrigin_ = [dragWindow_ frame].origin; |
| 233 } | 253 } |
| 234 } | 254 } |
| 235 | 255 |
| 236 // Create or identify the dragged controller. | 256 // Create or identify the dragged controller. |
| 237 if (!draggedController_) { | 257 if (!draggedController_) { |
| 238 if (isTheOnlyTab_) { | 258 // Detach from the current window and put it in a new window. |
| 239 draggedController_ = sourceController_; | 259 draggedController_ = [sourceController_ detachTabToNewWindow:self]; |
| 240 dragWindow_ = [draggedController_ window]; | 260 dragWindow_ = [draggedController_ window]; |
| 241 } else { | 261 [dragWindow_ setAlphaValue:0.0]; |
| 242 // Detach from the current window and put it in a new window. | |
| 243 draggedController_ = [sourceController_ detachTabToNewWindow:self]; | |
| 244 dragWindow_ = [draggedController_ window]; | |
| 245 [dragWindow_ setAlphaValue:0.0]; | |
| 246 } | |
| 247 | 262 |
| 263 // If dragging the tab only moves the current window, do not show overlay |
| 264 // so that sheets stay on top of the window. |
| 248 // Bring the target window to the front and make sure it has a border. | 265 // Bring the target window to the front and make sure it has a border. |
| 249 [dragWindow_ setLevel:NSFloatingWindowLevel]; | 266 [dragWindow_ setLevel:NSFloatingWindowLevel]; |
| 250 [dragWindow_ orderFront:nil]; | 267 [dragWindow_ orderFront:nil]; |
| 251 [dragWindow_ makeMainWindow]; | 268 [dragWindow_ makeMainWindow]; |
| 252 [draggedController_ showOverlay]; | 269 [draggedController_ showOverlay]; |
| 253 dragOverlay_ = [draggedController_ overlayWindow]; | 270 dragOverlay_ = [draggedController_ overlayWindow]; |
| 254 // Force the new tab button to be hidden. We'll reset it on mouse up. | 271 // Force the new tab button to be hidden. We'll reset it on mouse up. |
| 255 [draggedController_ showNewTabButton:NO]; | 272 [draggedController_ showNewTabButton:NO]; |
| 256 //if (![targets count]) | 273 //if (![targets count]) |
| 257 // [dragOverlay_ setHasShadow:NO]; | 274 // [dragOverlay_ setHasShadow:NO]; |
| 258 if (!isTheOnlyTab_) { | 275 tearTime_ = [NSDate timeIntervalSinceReferenceDate]; |
| 259 tearTime_ = [NSDate timeIntervalSinceReferenceDate]; | 276 tearOrigin_ = sourceWindowFrame_.origin; |
| 260 tearOrigin_ = sourceWindowFrame_.origin; | |
| 261 } | |
| 262 } | 277 } |
| 263 | 278 |
| 264 float tearProgress = [NSDate timeIntervalSinceReferenceDate] - tearTime_; | 279 float tearProgress = [NSDate timeIntervalSinceReferenceDate] - tearTime_; |
| 265 tearProgress /= kTearDuration; | 280 tearProgress /= kTearDuration; |
| 266 tearProgress = sqrtf(MAX(MIN(tearProgress, 1.0), 0.0)); | 281 tearProgress = sqrtf(MAX(MIN(tearProgress, 1.0), 0.0)); |
| 267 | 282 |
| 268 // Move the dragged window to the right place on the screen. | 283 // Move the dragged window to the right place on the screen. |
| 269 NSPoint origin = sourceWindowFrame_.origin; | 284 NSPoint origin = sourceWindowFrame_.origin; |
| 270 origin.x += (thisPoint.x - dragOrigin_.x); | 285 origin.x += (thisPoint.x - dragOrigin_.x); |
| 271 origin.y += (thisPoint.y - dragOrigin_.y); | 286 origin.y += (thisPoint.y - dragOrigin_.y); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 [[dragWindow_ animator] setAlphaValue:0.5]; | 356 [[dragWindow_ animator] setAlphaValue:0.5]; |
| 342 } | 357 } |
| 343 chromeIsVisible_ = chromeShouldBeVisible; | 358 chromeIsVisible_ = chromeShouldBeVisible; |
| 344 } | 359 } |
| 345 } | 360 } |
| 346 | 361 |
| 347 - (void)mouseUp:(NSEvent *)theEvent { | 362 - (void)mouseUp:(NSEvent *)theEvent { |
| 348 // The drag/click is done. If the user dragged the mouse, finalize the drag | 363 // The drag/click is done. If the user dragged the mouse, finalize the drag |
| 349 // and clean up. | 364 // and clean up. |
| 350 | 365 |
| 366 // Special-case this to keep the logic below simpler. |
| 367 if (moveWindowOnDrag_) |
| 368 return; |
| 369 |
| 351 // We are now free to re-display the new tab button in the window we're | 370 // We are now free to re-display the new tab button in the window we're |
| 352 // dragging. It will show when the next call to -layoutTabs (which happens | 371 // dragging. It will show when the next call to -layoutTabs (which happens |
| 353 // indrectly by several of the calls below, such as removing the placeholder). | 372 // indrectly by several of the calls below, such as removing the placeholder). |
| 354 [draggedController_ showNewTabButton:YES]; | 373 [draggedController_ showNewTabButton:YES]; |
| 355 | 374 |
| 356 if (draggingWithinTabStrip_) { | 375 if (draggingWithinTabStrip_) { |
| 357 if (tabWasDragged_) { | 376 if (tabWasDragged_) { |
| 358 // Move tab to new location. | 377 // Move tab to new location. |
| 359 TabWindowController* dropController = sourceController_; | 378 TabWindowController* dropController = sourceController_; |
| 360 [dropController moveTabView:[dropController selectedTabView] | 379 [dropController moveTabView:[dropController selectedTabView] |
| 361 fromController:nil]; | 380 fromController:nil]; |
| 362 } | 381 } |
| 363 } else if (targetController_) { | 382 } else if (targetController_) { |
| 364 // Move between windows. If |targetController_| is nil, we're not dropping | 383 // Move between windows. If |targetController_| is nil, we're not dropping |
| 365 // into any existing window. | 384 // into any existing window. |
| 366 NSView* draggedTabView = [draggedController_ selectedTabView]; | 385 NSView* draggedTabView = [draggedController_ selectedTabView]; |
| 367 [draggedController_ removeOverlay]; | 386 [draggedController_ removeOverlay]; |
| 368 [targetController_ moveTabView:draggedTabView | 387 [targetController_ moveTabView:draggedTabView |
| 369 fromController:draggedController_]; | 388 fromController:draggedController_]; |
| 370 [targetController_ showWindow:nil]; | 389 [targetController_ showWindow:nil]; |
| 371 } else { | 390 } else { |
| 391 // Tab dragging did move window only. |
| 372 [dragWindow_ setAlphaValue:1.0]; | 392 [dragWindow_ setAlphaValue:1.0]; |
| 373 [dragOverlay_ setHasShadow:NO]; | 393 [dragOverlay_ setHasShadow:NO]; |
| 374 [dragWindow_ setHasShadow:YES]; | 394 [dragWindow_ setHasShadow:YES]; |
| 375 [draggedController_ removeOverlay]; | 395 [draggedController_ removeOverlay]; |
| 376 [dragWindow_ makeKeyAndOrderFront:nil]; | 396 [dragWindow_ makeKeyAndOrderFront:nil]; |
| 377 | 397 |
| 378 [[draggedController_ window] setLevel:NSNormalWindowLevel]; | 398 [[draggedController_ window] setLevel:NSNormalWindowLevel]; |
| 379 [draggedController_ removePlaceholder]; | 399 [draggedController_ removePlaceholder]; |
| 380 } | 400 } |
| 381 [sourceController_ removePlaceholder]; | 401 [sourceController_ removePlaceholder]; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 [[NSGraphicsContext currentContext] restoreGraphicsState]; | 524 [[NSGraphicsContext currentContext] restoreGraphicsState]; |
| 505 } | 525 } |
| 506 | 526 |
| 507 // Called when the user hits the right mouse button (or control-clicks) to | 527 // Called when the user hits the right mouse button (or control-clicks) to |
| 508 // show a context menu. | 528 // show a context menu. |
| 509 - (void)rightMouseDown:(NSEvent*)theEvent { | 529 - (void)rightMouseDown:(NSEvent*)theEvent { |
| 510 [NSMenu popUpContextMenu:[self menu] withEvent:theEvent forView:self]; | 530 [NSMenu popUpContextMenu:[self menu] withEvent:theEvent forView:self]; |
| 511 } | 531 } |
| 512 | 532 |
| 513 @end | 533 @end |
| OLD | NEW |