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/tab_view.h" | 5 #import "chrome/browser/cocoa/tab_view.h" |
6 | 6 |
7 #include "base/logging.h" | |
7 #include "chrome/browser/cocoa/nsimage_cache.h" | 8 #include "chrome/browser/cocoa/nsimage_cache.h" |
8 #include "chrome/browser/cocoa/tab_controller.h" | 9 #import "chrome/browser/cocoa/tab_controller.h" |
9 #include "chrome/browser/cocoa/tab_window_controller.h" | 10 #import "chrome/browser/cocoa/tab_window_controller.h" |
10 | 11 |
11 // Constants for inset and control points for tab shape. | 12 // Constants for inset and control points for tab shape. |
12 static const CGFloat kInsetMultiplier = 2.0/3.0; | 13 static const CGFloat kInsetMultiplier = 2.0/3.0; |
13 static const CGFloat kControlPoint1Multiplier = 1.0/3.0; | 14 static const CGFloat kControlPoint1Multiplier = 1.0/3.0; |
14 static const CGFloat kControlPoint2Multiplier = 3.0/8.0; | 15 static const CGFloat kControlPoint2Multiplier = 3.0/8.0; |
15 | 16 |
16 static const NSTimeInterval kAnimationShowDuration = 0.2; | 17 static const NSTimeInterval kAnimationShowDuration = 0.2; |
17 static const NSTimeInterval kAnimationHideDuration = 0.4; | 18 static const NSTimeInterval kAnimationHideDuration = 0.4; |
18 | 19 |
19 @implementation TabView | 20 @implementation TabView |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 - (BOOL)canBeDragged { | 136 - (BOOL)canBeDragged { |
136 NSWindowController *controller = [sourceWindow_ windowController]; | 137 NSWindowController *controller = [sourceWindow_ windowController]; |
137 if ([controller isKindOfClass:[TabWindowController class]]) { | 138 if ([controller isKindOfClass:[TabWindowController class]]) { |
138 TabWindowController* realController = | 139 TabWindowController* realController = |
139 static_cast<TabWindowController*>(controller); | 140 static_cast<TabWindowController*>(controller); |
140 return [realController isTabDraggable:self]; | 141 return [realController isTabDraggable:self]; |
141 } | 142 } |
142 return YES; | 143 return YES; |
143 } | 144 } |
144 | 145 |
146 // Find all the windows that could be a target. It has to be of the | |
147 // appropriate class, and visible (obviously). Note that the window cannot be | |
148 // a target for itself. | |
149 - (NSArray*)dropTargetsForController:(TabWindowController*)dragController { | |
150 NSMutableArray* targets = [NSMutableArray array]; | |
151 NSWindow* dragWindow = [dragController window]; | |
152 for (NSWindow* window in [NSApp windows]) { | |
153 if (window == dragWindow) continue; | |
154 if (![window isVisible]) continue; | |
155 NSWindowController *controller = [window windowController]; | |
156 if ([controller isKindOfClass:[TabWindowController class]]) { | |
157 TabWindowController* realController = | |
158 static_cast<TabWindowController*>(controller); | |
159 if ([realController canReceiveFrom:dragController]) { | |
160 [targets addObject:controller]; | |
161 } | |
162 } | |
163 } | |
164 return targets; | |
165 } | |
166 | |
145 // Handle clicks and drags in this button. We get here because we have | 167 // Handle clicks and drags in this button. We get here because we have |
146 // overridden acceptsFirstMouse: and the click is within our bounds. | 168 // overridden acceptsFirstMouse: and the click is within our bounds. |
147 // TODO(pinkerton/alcor): This routine needs *a lot* of work to marry Cole's | 169 // TODO(pinkerton/alcor): This routine needs *a lot* of work to marry Cole's |
148 // ideas of dragging cocoa views between windows and how the Browser and | 170 // ideas of dragging cocoa views between windows and how the Browser and |
149 // TabStrip models want to manage tabs. | 171 // TabStrip models want to manage tabs. |
150 | 172 |
151 static const CGFloat kTearDistance = 36.0; | 173 static const CGFloat kTearDistance = 36.0; |
152 static const NSTimeInterval kTearDuration = 0.333; | 174 static const NSTimeInterval kTearDuration = 0.333; |
153 | 175 |
154 // This is used to judge whether the mouse has moved during rapid closure; if it | 176 // This is used to judge whether the mouse has moved during rapid closure; if it |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
186 sourceTabFrame_ = [self frame]; | 208 sourceTabFrame_ = [self frame]; |
187 sourceController_ = [sourceWindow_ windowController]; | 209 sourceController_ = [sourceWindow_ windowController]; |
188 draggedController_ = nil; | 210 draggedController_ = nil; |
189 dragWindow_ = nil; | 211 dragWindow_ = nil; |
190 dragOverlay_ = nil; | 212 dragOverlay_ = nil; |
191 targetController_ = nil; | 213 targetController_ = nil; |
192 tabWasDragged_ = NO; | 214 tabWasDragged_ = NO; |
193 tearTime_ = 0.0; | 215 tearTime_ = 0.0; |
194 draggingWithinTabStrip_ = YES; | 216 draggingWithinTabStrip_ = YES; |
195 | 217 |
196 // We don't want to "tear off" a tab if there's only one in the window. Treat | 218 // If there's more than one potential window to be a drop target, we want to |
197 // it like we're dragging around a tab we've already detached. Note that | 219 // treat a drag of a tab just like dragging around a tab that's already |
198 // unit tests might have |-numberOfTabs| reporting zero since the model | 220 // detached. Note that unit tests might have |-numberOfTabs| reporting zero |
199 // won't be fully hooked up. We need to be prepared for that and not send | 221 // since the model won't be fully hooked up. We need to be prepared for that |
200 // them into the "magnetic" codepath. | 222 // and not send them into the "magnetic" codepath. |
223 NSArray* targets = [self dropTargetsForController:sourceController_]; | |
201 moveWindowOnDrag_ = | 224 moveWindowOnDrag_ = |
202 [sourceController_ numberOfTabs] <= 1 || ![self canBeDragged]; | 225 ([sourceController_ numberOfTabs] < 2 && ![targets count]) || |
226 ![self canBeDragged]; | |
rohitrao (ping after 24h)
2009/09/10 19:03:56
Should this be in line with the "(" above?
pink (ping after 24hrs)
2009/09/10 19:05:55
No, the first two should bind together, or'd with
pink (ping after 24hrs)
2009/09/10 19:06:31
Oops, my bad, yes. Misunderstood.
| |
227 // If we are dragging a tab, a window with a single tab should immediately | |
228 // snap off and not drag within the tab strip. | |
229 if (!moveWindowOnDrag_) | |
230 draggingWithinTabStrip_ = [sourceController_ numberOfTabs] > 1; | |
203 | 231 |
204 dragOrigin_ = [NSEvent mouseLocation]; | 232 dragOrigin_ = [NSEvent mouseLocation]; |
205 | 233 |
206 // Because we move views between windows, we need to handle the event loop | 234 // Because we move views between windows, we need to handle the event loop |
207 // ourselves. Ideally we should use the standard event loop. | 235 // ourselves. Ideally we should use the standard event loop. |
208 while (1) { | 236 while (1) { |
209 theEvent = | 237 theEvent = |
210 [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask | 238 [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask |
211 untilDate:[NSDate distantFuture] | 239 untilDate:[NSDate distantFuture] |
212 inMode:NSDefaultRunLoopMode dequeue:YES]; | 240 inMode:NSDefaultRunLoopMode dequeue:YES]; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 } else { | 307 } else { |
280 return; | 308 return; |
281 } | 309 } |
282 } | 310 } |
283 | 311 |
284 NSPoint lastPoint = | 312 NSPoint lastPoint = |
285 [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]]; | 313 [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]]; |
286 | 314 |
287 // Do not start dragging until the user has "torn" the tab off by | 315 // Do not start dragging until the user has "torn" the tab off by |
288 // moving more than 3 pixels. | 316 // moving more than 3 pixels. |
289 NSDate* targetDwellDate = nil; // The date this target was first chosen | 317 NSDate* targetDwellDate = nil; // The date this target was first chosen. |
290 NSMutableArray* targets = [NSMutableArray array]; | |
291 | 318 |
292 NSPoint thisPoint = [NSEvent mouseLocation]; | 319 NSPoint thisPoint = [NSEvent mouseLocation]; |
293 | 320 |
294 // Find all the windows that could be a target. It has to be of the | |
295 // appropriate class, and visible (obviously). | |
296 if (![targets count]) { | |
297 for (NSWindow* window in [NSApp windows]) { | |
298 if (window == dragWindow_) continue; | |
299 if (![window isVisible]) continue; | |
300 NSWindowController *controller = [window windowController]; | |
301 if ([controller isKindOfClass:[TabWindowController class]]) { | |
302 TabWindowController* realController = | |
303 static_cast<TabWindowController*>(controller); | |
304 if ([realController canReceiveFrom:sourceController_]) { | |
305 [targets addObject:controller]; | |
306 } | |
307 } | |
308 } | |
309 } | |
310 | |
311 // Iterate over possible targets checking for the one the mouse is in. | 321 // Iterate over possible targets checking for the one the mouse is in. |
312 // The mouse can be in either the tab or window frame. | 322 // The mouse can be in either the tab or window frame. |
323 NSArray* targets = [self dropTargetsForController:draggedController_]; | |
313 TabWindowController* newTarget = nil; | 324 TabWindowController* newTarget = nil; |
314 for (TabWindowController* target in targets) { | 325 for (TabWindowController* target in targets) { |
315 NSRect windowFrame = [[target window] frame]; | 326 NSRect windowFrame = [[target window] frame]; |
316 if (NSPointInRect(thisPoint, windowFrame)) { | 327 if (NSPointInRect(thisPoint, windowFrame)) { |
317 NSRect tabStripFrame = [[target tabStripView] frame]; | 328 NSRect tabStripFrame = [[target tabStripView] frame]; |
318 tabStripFrame.origin = [[target window] | 329 tabStripFrame.origin = [[target window] |
319 convertBaseToScreen:tabStripFrame.origin]; | 330 convertBaseToScreen:tabStripFrame.origin]; |
320 if (NSPointInRect(thisPoint, tabStripFrame)) { | 331 if (NSPointInRect(thisPoint, tabStripFrame)) { |
321 newTarget = target; | 332 newTarget = target; |
322 } | 333 } |
323 break; | 334 break; |
324 } | 335 } |
325 } | 336 } |
326 | 337 |
327 // If we're now targeting a new window, re-layout the tabs in the old | 338 // If we're now targeting a new window, re-layout the tabs in the old |
328 // target and reset how long we've been hovering over this new one. | 339 // target and reset how long we've been hovering over this new one. |
329 if (targetController_ != newTarget) { | 340 if (targetController_ != newTarget) { |
330 targetDwellDate = [NSDate date]; | 341 targetDwellDate = [NSDate date]; |
331 [targetController_ removePlaceholder]; | 342 [targetController_ removePlaceholder]; |
332 targetController_ = newTarget; | 343 targetController_ = newTarget; |
333 if (!newTarget) { | 344 if (!newTarget) { |
334 tearTime_ = [NSDate timeIntervalSinceReferenceDate]; | 345 tearTime_ = [NSDate timeIntervalSinceReferenceDate]; |
335 tearOrigin_ = [dragWindow_ frame].origin; | 346 tearOrigin_ = [dragWindow_ frame].origin; |
336 } | 347 } |
337 } | 348 } |
338 | 349 |
339 // Create or identify the dragged controller. | 350 // Create or identify the dragged controller. |
340 if (!draggedController_) { | 351 if (!draggedController_) { |
341 // Detach from the current window and put it in a new window. | 352 // Detach from the current window and put it in a new window. If there are |
353 // no more tabs remaining after detaching, the source window is about to | |
354 // go away (it's been autoreleased) so we need to ensure we don't reference | |
355 // it any more. In that case the new controller becomes our source | |
356 // controller. | |
342 draggedController_ = [sourceController_ detachTabToNewWindow:self]; | 357 draggedController_ = [sourceController_ detachTabToNewWindow:self]; |
343 dragWindow_ = [draggedController_ window]; | 358 dragWindow_ = [draggedController_ window]; |
344 [dragWindow_ setAlphaValue:0.0]; | 359 [dragWindow_ setAlphaValue:0.0]; |
360 if (![sourceController_ numberOfTabs]) { | |
361 sourceController_ = draggedController_; | |
362 sourceWindow_ = dragWindow_; | |
363 } | |
345 | 364 |
346 // If dragging the tab only moves the current window, do not show overlay | 365 // If dragging the tab only moves the current window, do not show overlay |
347 // so that sheets stay on top of the window. | 366 // so that sheets stay on top of the window. |
348 // Bring the target window to the front and make sure it has a border. | 367 // Bring the target window to the front and make sure it has a border. |
349 [dragWindow_ setLevel:NSFloatingWindowLevel]; | 368 [dragWindow_ setLevel:NSFloatingWindowLevel]; |
350 [dragWindow_ orderFront:nil]; | 369 [dragWindow_ orderFront:nil]; |
351 [dragWindow_ makeMainWindow]; | 370 [dragWindow_ makeMainWindow]; |
352 [draggedController_ showOverlay]; | 371 [draggedController_ showOverlay]; |
353 dragOverlay_ = [draggedController_ overlayWindow]; | 372 dragOverlay_ = [draggedController_ overlayWindow]; |
354 // Force the new tab button to be hidden. We'll reset it on mouse up. | 373 // Force the new tab button to be hidden. We'll reset it on mouse up. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
391 } | 410 } |
392 [dragWindow_ setFrameOrigin:NSMakePoint(origin.x, origin.y)]; | 411 [dragWindow_ setFrameOrigin:NSMakePoint(origin.x, origin.y)]; |
393 | 412 |
394 // If we're not hovering over any window, make the window is fully | 413 // If we're not hovering over any window, make the window is fully |
395 // opaque. Otherwise, find where the tab might be dropped and insert | 414 // opaque. Otherwise, find where the tab might be dropped and insert |
396 // a placeholder so it appears like it's part of that window. | 415 // a placeholder so it appears like it's part of that window. |
397 if (targetController_) { | 416 if (targetController_) { |
398 if (![[targetController_ window] isKeyWindow]) { | 417 if (![[targetController_ window] isKeyWindow]) { |
399 // && ([targetDwellDate timeIntervalSinceNow] < -REQUIRED_DWELL)) { | 418 // && ([targetDwellDate timeIntervalSinceNow] < -REQUIRED_DWELL)) { |
400 [[targetController_ window] orderFront:nil]; | 419 [[targetController_ window] orderFront:nil]; |
401 [targets removeAllObjects]; | |
rohitrao (ping after 24h)
2009/09/10 19:03:56
This is ok to delete because targets is never refe
pink (ping after 24hrs)
2009/09/10 19:05:55
Correct. It must have been leftover from something
| |
402 targetDwellDate = nil; | 420 targetDwellDate = nil; |
403 } | 421 } |
404 | 422 |
405 // Compute where placeholder should go and insert it into the | 423 // Compute where placeholder should go and insert it into the |
406 // destination tab strip. | 424 // destination tab strip. |
407 NSRect dropTabFrame = [[targetController_ tabStripView] frame]; | 425 NSRect dropTabFrame = [[targetController_ tabStripView] frame]; |
408 TabView *draggedTabView = (TabView *)[draggedController_ selectedTabView]; | 426 TabView *draggedTabView = (TabView *)[draggedController_ selectedTabView]; |
409 NSRect tabFrame = [draggedTabView frame]; | 427 NSRect tabFrame = [draggedTabView frame]; |
410 tabFrame.origin = [dragWindow_ convertBaseToScreen:tabFrame.origin]; | 428 tabFrame.origin = [dragWindow_ convertBaseToScreen:tabFrame.origin]; |
411 tabFrame.origin = [[targetController_ window] | 429 tabFrame.origin = [[targetController_ window] |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
451 return; | 469 return; |
452 | 470 |
453 // We are now free to re-display the new tab button in the window we're | 471 // We are now free to re-display the new tab button in the window we're |
454 // dragging. It will show when the next call to -layoutTabs (which happens | 472 // dragging. It will show when the next call to -layoutTabs (which happens |
455 // indrectly by several of the calls below, such as removing the placeholder). | 473 // indrectly by several of the calls below, such as removing the placeholder). |
456 [draggedController_ showNewTabButton:YES]; | 474 [draggedController_ showNewTabButton:YES]; |
457 | 475 |
458 if (draggingWithinTabStrip_) { | 476 if (draggingWithinTabStrip_) { |
459 if (tabWasDragged_) { | 477 if (tabWasDragged_) { |
460 // Move tab to new location. | 478 // Move tab to new location. |
479 DCHECK([sourceController_ numberOfTabs]); | |
461 TabWindowController* dropController = sourceController_; | 480 TabWindowController* dropController = sourceController_; |
462 [dropController moveTabView:[dropController selectedTabView] | 481 [dropController moveTabView:[dropController selectedTabView] |
463 fromController:nil]; | 482 fromController:nil]; |
464 } | 483 } |
465 } else if (targetController_) { | 484 } else if (targetController_) { |
466 // Move between windows. If |targetController_| is nil, we're not dropping | 485 // Move between windows. If |targetController_| is nil, we're not dropping |
467 // into any existing window. | 486 // into any existing window. |
468 NSView* draggedTabView = [draggedController_ selectedTabView]; | 487 NSView* draggedTabView = [draggedController_ selectedTabView]; |
469 [draggedController_ removeOverlay]; | 488 [draggedController_ removeOverlay]; |
470 [targetController_ moveTabView:draggedTabView | 489 [targetController_ moveTabView:draggedTabView |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
652 [[NSGraphicsContext currentContext] restoreGraphicsState]; | 671 [[NSGraphicsContext currentContext] restoreGraphicsState]; |
653 } | 672 } |
654 | 673 |
655 // Called when the user hits the right mouse button (or control-clicks) to | 674 // Called when the user hits the right mouse button (or control-clicks) to |
656 // show a context menu. | 675 // show a context menu. |
657 - (void)rightMouseDown:(NSEvent*)theEvent { | 676 - (void)rightMouseDown:(NSEvent*)theEvent { |
658 [NSMenu popUpContextMenu:[self menu] withEvent:theEvent forView:self]; | 677 [NSMenu popUpContextMenu:[self menu] withEvent:theEvent forView:self]; |
659 } | 678 } |
660 | 679 |
661 @end | 680 @end |
OLD | NEW |