Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: chrome/browser/ui/cocoa/download/download_shelf_controller.mm

Issue 13318002: [Mac] Fix handling of download shelf auto close. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Use OCMock Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/ui/cocoa/download/download_shelf_controller.h" 5 #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
6 6
7 #include "base/mac/bundle_locations.h" 7 #include "base/mac/bundle_locations.h"
8 #include "base/mac/mac_util.h" 8 #include "base/mac/mac_util.h"
9 #include "base/strings/sys_string_conversions.h" 9 #include "base/strings/sys_string_conversions.h"
10 #include "chrome/browser/download/download_util.h" 10 #include "chrome/browser/download/download_util.h"
(...skipping 13 matching lines...) Expand all
24 #include "content/public/browser/download_manager.h" 24 #include "content/public/browser/download_manager.h"
25 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" 25 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
26 #import "ui/base/cocoa/hover_button.h" 26 #import "ui/base/cocoa/hover_button.h"
27 #include "ui/base/l10n/l10n_util.h" 27 #include "ui/base/l10n/l10n_util.h"
28 28
29 using content::DownloadItem; 29 using content::DownloadItem;
30 30
31 // Download shelf autoclose behavior: 31 // Download shelf autoclose behavior:
32 // 32 //
33 // The download shelf autocloses if all of this is true: 33 // The download shelf autocloses if all of this is true:
34 // 1) An item on the shelf has just been opened. 34 // 1) An item on the shelf has just been opened or removed.
35 // 2) All remaining items on the shelf have been opened in the past. 35 // 2) All remaining items on the shelf have been opened in the past.
36 // 3) The mouse leaves the shelf and remains off the shelf for 5 seconds. 36 // 3) The mouse leaves the shelf and remains off the shelf for 5 seconds.
37 // 37 //
38 // If the mouse re-enters the shelf within the 5 second grace period, the 38 // If the mouse re-enters the shelf within the 5 second grace period, the
39 // autoclose is canceled. An autoclose can only be scheduled in response to a 39 // autoclose is canceled. An autoclose can only be scheduled in response to a
40 // shelf item being opened or removed. If an item is opened and then the 40 // shelf item being opened or removed. If an item is opened and then the
41 // resulting autoclose is canceled, subsequent mouse exited events will NOT 41 // resulting autoclose is canceled, subsequent mouse exited events will NOT
42 // trigger an autoclose. 42 // trigger an autoclose.
43 // 43 //
44 // If the shelf is manually closed while a download is still in progress, that 44 // If the shelf is manually closed while a download is still in progress, that
(...skipping 19 matching lines...) Expand all
64 // Amount of time between when the mouse is moved off the shelf and the shelf is 64 // Amount of time between when the mouse is moved off the shelf and the shelf is
65 // autoclosed, in seconds. 65 // autoclosed, in seconds.
66 const NSTimeInterval kAutoCloseDelaySeconds = 5; 66 const NSTimeInterval kAutoCloseDelaySeconds = 5;
67 67
68 // The size of the x button by default. 68 // The size of the x button by default.
69 const NSSize kHoverCloseButtonDefaultSize = { 18, 18 }; 69 const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
70 70
71 } // namespace 71 } // namespace
72 72
73 @interface DownloadShelfController(Private) 73 @interface DownloadShelfController(Private)
74 - (void)removeDownload:(DownloadItemController*)download
75 isShelfClosing:(BOOL)isShelfClosing;
74 - (void)layoutItems:(BOOL)skipFirst; 76 - (void)layoutItems:(BOOL)skipFirst;
75 - (void)closed; 77 - (void)closed;
76 - (void)maybeAutoCloseAfterDelay; 78 - (void)maybeAutoCloseAfterDelay;
79 - (void)scheduleAutoClose;
80 - (void)cancelAutoClose;
77 - (void)autoClose; 81 - (void)autoClose;
78 - (void)viewFrameDidChange:(NSNotification*)notification; 82 - (void)viewFrameDidChange:(NSNotification*)notification;
79 - (void)installTrackingArea; 83 - (void)installTrackingArea;
80 - (void)cancelAutoCloseAndRemoveTrackingArea; 84 - (void)removeTrackingArea;
81 - (void)willEnterFullscreen; 85 - (void)willEnterFullscreen;
82 - (void)willLeaveFullscreen; 86 - (void)willLeaveFullscreen;
83 - (void)updateCloseButton; 87 - (void)updateCloseButton;
84 @end 88 @end
85 89
86 90
87 @implementation DownloadShelfController 91 @implementation DownloadShelfController
88 92
89 - (id)initWithBrowser:(Browser*)browser 93 - (id)initWithBrowser:(Browser*)browser
90 resizeDelegate:(id<ViewResizer>)resizeDelegate { 94 resizeDelegate:(id<ViewResizer>)resizeDelegate {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 // These notifications are declared in fullscreen_controller, and are posted 133 // These notifications are declared in fullscreen_controller, and are posted
130 // without objects. 134 // without objects.
131 [defaultCenter addObserver:self 135 [defaultCenter addObserver:self
132 selector:@selector(willEnterFullscreen) 136 selector:@selector(willEnterFullscreen)
133 name:kWillEnterFullscreenNotification 137 name:kWillEnterFullscreenNotification
134 object:nil]; 138 object:nil];
135 [defaultCenter addObserver:self 139 [defaultCenter addObserver:self
136 selector:@selector(willLeaveFullscreen) 140 selector:@selector(willLeaveFullscreen)
137 name:kWillLeaveFullscreenNotification 141 name:kWillLeaveFullscreenNotification
138 object:nil]; 142 object:nil];
143 [self installTrackingArea];
139 } 144 }
140 145
141 - (void)dealloc { 146 - (void)dealloc {
142 [[NSNotificationCenter defaultCenter] removeObserver:self]; 147 [[NSNotificationCenter defaultCenter] removeObserver:self];
143 [self cancelAutoCloseAndRemoveTrackingArea]; 148 [self removeTrackingArea];
144 149
145 // The controllers will unregister themselves as observers when they are 150 // The controllers will unregister themselves as observers when they are
146 // deallocated. No need to do that here. 151 // deallocated. No need to do that here.
147 [super dealloc]; 152 [super dealloc];
148 } 153 }
149 154
150 // Called after the frame's rect has changed; usually when the height is 155 // Called after the frame's rect has changed; usually when the height is
151 // animated. 156 // animated.
152 - (void)viewFrameDidChange:(NSNotification*)notification { 157 - (void)viewFrameDidChange:(NSNotification*)notification {
153 // Anchor subviews at the top of |view|, so that it looks like the shelf 158 // Anchor subviews at the top of |view|, so that it looks like the shelf
(...skipping 16 matching lines...) Expand all
170 175
171 - (IBAction)showDownloadsTab:(id)sender { 176 - (IBAction)showDownloadsTab:(id)sender {
172 chrome::ShowDownloads(bridge_->browser()); 177 chrome::ShowDownloads(bridge_->browser());
173 } 178 }
174 179
175 - (IBAction)handleClose:(id)sender { 180 - (IBAction)handleClose:(id)sender {
176 bridge_->Close(DownloadShelf::USER_ACTION); 181 bridge_->Close(DownloadShelf::USER_ACTION);
177 } 182 }
178 183
179 - (void)remove:(DownloadItemController*)download { 184 - (void)remove:(DownloadItemController*)download {
185 [self removeDownload:download
186 isShelfClosing:NO];
187 }
188
189 - (void)removeDownload:(DownloadItemController*)download
190 isShelfClosing:(BOOL)isShelfClosing {
180 // Look for the download in our controller array and remove it. This will 191 // Look for the download in our controller array and remove it. This will
181 // explicity release it so that it removes itself as an Observer of the 192 // explicity release it so that it removes itself as an Observer of the
182 // DownloadItem. We don't want to wait for autorelease since the DownloadItem 193 // DownloadItem. We don't want to wait for autorelease since the DownloadItem
183 // we are observing will likely be gone by then. 194 // we are observing will likely be gone by then.
184 [[NSNotificationCenter defaultCenter] removeObserver:download]; 195 [[NSNotificationCenter defaultCenter] removeObserver:download];
185 196
186 // TODO(dmaclach): Remove -- http://crbug.com/25845 197 // TODO(dmaclach): Remove -- http://crbug.com/25845
187 [[download view] removeFromSuperview]; 198 [[download view] removeFromSuperview];
188 199
189 [downloadItemControllers_ removeObject:download]; 200 [downloadItemControllers_ removeObject:download];
190 [self layoutItems];
191 201
192 // If there are no more downloads or if all the remaining downloads have been 202 if (!isShelfClosing) {
193 // opened, we can close the shelf. 203 [self layoutItems];
194 [self maybeAutoCloseAfterDelay]; 204
205 // If there are no more downloads or if all the remaining downloads have
206 // been opened, we can close the shelf.
207 [self maybeAutoCloseAfterDelay];
208 }
195 } 209 }
196 210
197 - (void)downloadWasOpened:(DownloadItemController*)item_controller { 211 - (void)downloadWasOpened:(DownloadItemController*)item_controller {
198 // This should only be called on the main thead. 212 // This should only be called on the main thead.
199 DCHECK([NSThread isMainThread]); 213 DCHECK([NSThread isMainThread]);
200 [self maybeAutoCloseAfterDelay]; 214 [self maybeAutoCloseAfterDelay];
201 } 215 }
202 216
203 // We need to explicitly release our download controllers here since they need 217 // We need to explicitly release our download controllers here since they need
204 // to remove themselves as observers before the remaining shutdown happens. 218 // to remove themselves as observers before the remaining shutdown happens.
205 - (void)exiting { 219 - (void)exiting {
206 [[self animatableView] stopAnimation]; 220 [[self animatableView] stopAnimation];
207 [self cancelAutoCloseAndRemoveTrackingArea]; 221 [self removeTrackingArea];
222 while ([downloadItemControllers_ count] > 0) {
223 [self removeDownload:[downloadItemControllers_ lastObject]
224 isShelfClosing:YES];
225 }
208 downloadItemControllers_.reset(); 226 downloadItemControllers_.reset();
209 } 227 }
210 228
211 - (void)showDownloadShelf:(BOOL)show 229 - (void)showDownloadShelf:(BOOL)show
212 isUserAction:(BOOL)isUserAction { 230 isUserAction:(BOOL)isUserAction {
231 shouldCloseOnMouseExit_ = NO;
232
213 if ([self isVisible] == show) 233 if ([self isVisible] == show)
214 return; 234 return;
215 235
216 if (!show) { 236 if (!show) {
217 [self cancelAutoCloseAndRemoveTrackingArea];
218 int numInProgress = 0; 237 int numInProgress = 0;
219 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) { 238 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) {
220 if ([[downloadItemControllers_ objectAtIndex:i]download]->IsInProgress()) 239 if ([[downloadItemControllers_ objectAtIndex:i]download]->IsInProgress())
221 ++numInProgress; 240 ++numInProgress;
222 } 241 }
223 download_util::RecordShelfClose( 242 download_util::RecordShelfClose(
224 [downloadItemControllers_ count], numInProgress, !isUserAction); 243 [downloadItemControllers_ count], numInProgress, !isUserAction);
225 } 244 }
226 245
227 // Animate the shelf out, but not in. 246 // Animate the shelf out, but not in.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 skipFirst = NO; 289 skipFirst = NO;
271 } 290 }
272 } 291 }
273 292
274 - (void)layoutItems { 293 - (void)layoutItems {
275 [self layoutItems:NO]; 294 [self layoutItems:NO];
276 } 295 }
277 296
278 - (void)addDownloadItem:(DownloadItem*)downloadItem { 297 - (void)addDownloadItem:(DownloadItem*)downloadItem {
279 DCHECK([NSThread isMainThread]); 298 DCHECK([NSThread isMainThread]);
280 [self cancelAutoCloseAndRemoveTrackingArea];
281
282 // Insert new item at the left.
283 scoped_nsobject<DownloadItemController> controller( 299 scoped_nsobject<DownloadItemController> controller(
284 [[DownloadItemController alloc] initWithDownload:downloadItem 300 [[DownloadItemController alloc] initWithDownload:downloadItem
285 shelf:self 301 shelf:self
286 navigator:navigator_]); 302 navigator:navigator_]);
303 [self add:controller.get()];
304 }
287 305
306 - (void)add:(DownloadItemController*)controller {
307 DCHECK([NSThread isMainThread]);
308 shouldCloseOnMouseExit_ = NO;
309
310 // Insert new item at the left.
288 // Adding at index 0 in NSMutableArrays is O(1). 311 // Adding at index 0 in NSMutableArrays is O(1).
289 [downloadItemControllers_ insertObject:controller.get() atIndex:0]; 312 [downloadItemControllers_ insertObject:controller atIndex:0];
290 313
291 [itemContainerView_ addSubview:[controller view]]; 314 [itemContainerView_ addSubview:[controller view]];
292 315
293 // The controller is in charge of removing itself as an observer in its 316 // The controller is in charge of removing itself as an observer in its
294 // dealloc. 317 // dealloc.
295 [[NSNotificationCenter defaultCenter] 318 [[NSNotificationCenter defaultCenter]
296 addObserver:controller 319 addObserver:controller
297 selector:@selector(updateVisibility:) 320 selector:@selector(updateVisibility:)
298 name:NSViewFrameDidChangeNotification 321 name:NSViewFrameDidChangeNotification
299 object:[controller view]]; 322 object:[controller view]];
(...skipping 17 matching lines...) Expand all
317 [[[controller view] animator] setFrame:frame]; 340 [[[controller view] animator] setFrame:frame];
318 [NSAnimationContext endGrouping]; 341 [NSAnimationContext endGrouping];
319 342
320 // Keep only a limited number of items in the shelf. 343 // Keep only a limited number of items in the shelf.
321 if ([downloadItemControllers_ count] > kMaxDownloadItemCount) { 344 if ([downloadItemControllers_ count] > kMaxDownloadItemCount) {
322 DCHECK(kMaxDownloadItemCount > 0); 345 DCHECK(kMaxDownloadItemCount > 0);
323 346
324 // Since no user will ever see the item being removed (needs a horizontal 347 // Since no user will ever see the item being removed (needs a horizontal
325 // screen resolution greater than 3200 at 16 items at 200 pixels each), 348 // screen resolution greater than 3200 at 16 items at 200 pixels each),
326 // there's no point in animating the removal. 349 // there's no point in animating the removal.
327 [self remove:[downloadItemControllers_ lastObject]]; 350 [self removeDownload:[downloadItemControllers_ lastObject]
351 isShelfClosing:NO];
328 } 352 }
329 353
330 // Finally, move the remaining items to the right. Skip the first item when 354 // Finally, move the remaining items to the right. Skip the first item when
331 // laying out the items, so that the longer animation duration we set up above 355 // laying out the items, so that the longer animation duration we set up above
332 // is not overwritten. 356 // is not overwritten.
333 [self layoutItems:YES]; 357 [self layoutItems:YES];
334 } 358 }
335 359
336 - (void)closed { 360 - (void)closed {
337 // Don't remove completed downloads if the shelf is just being auto-hidden 361 // Don't remove completed downloads if the shelf is just being auto-hidden
338 // rather than explicitly closed by the user. 362 // rather than explicitly closed by the user.
339 if (bridge_->is_hidden()) 363 if (bridge_->is_hidden())
340 return; 364 return;
341 NSUInteger i = 0; 365 NSUInteger i = 0;
342 while (i < [downloadItemControllers_ count]) { 366 while (i < [downloadItemControllers_ count]) {
343 DownloadItemController* itemController = 367 DownloadItemController* itemController =
344 [downloadItemControllers_ objectAtIndex:i]; 368 [downloadItemControllers_ objectAtIndex:i];
345 DownloadItem* download = [itemController download]; 369 DownloadItem* download = [itemController download];
346 bool isTransferDone = download->IsComplete() || 370 bool isTransferDone = download->IsComplete() ||
347 download->IsCancelled() || 371 download->IsCancelled() ||
348 download->IsInterrupted(); 372 download->IsInterrupted();
349 if (isTransferDone && !download->IsDangerous()) { 373 if (isTransferDone && !download->IsDangerous()) {
350 [self remove:itemController]; 374 [self removeDownload:itemController
375 isShelfClosing:YES];
351 } else { 376 } else {
352 // Treat the item as opened when we close. This way if we get shown again 377 // Treat the item as opened when we close. This way if we get shown again
353 // the user need not open this item for the shelf to auto-close. 378 // the user need not open this item for the shelf to auto-close.
354 download->SetOpened(true); 379 download->SetOpened(true);
355 ++i; 380 ++i;
356 } 381 }
357 } 382 }
358 } 383 }
359 384
360 - (void)mouseEntered:(NSEvent*)event { 385 - (void)mouseEntered:(NSEvent*)event {
386 isMouseInsideView_ = YES;
361 // If the mouse re-enters the download shelf, cancel the auto-close. Further 387 // If the mouse re-enters the download shelf, cancel the auto-close. Further
362 // mouse exits should not trigger autoclose, so also remove the tracking area. 388 // mouse exits should not trigger autoclose.
363 [self cancelAutoCloseAndRemoveTrackingArea]; 389 if (shouldCloseOnMouseExit_) {
390 [self cancelAutoClose];
391 shouldCloseOnMouseExit_ = NO;
392 }
364 } 393 }
365 394
366 - (void)mouseExited:(NSEvent*)event { 395 - (void)mouseExited:(NSEvent*)event {
396 isMouseInsideView_ = NO;
397 if (shouldCloseOnMouseExit_)
398 [self scheduleAutoClose];
399 }
400
401 - (void)scheduleAutoClose {
367 // Cancel any previous hide requests, just to be safe. 402 // Cancel any previous hide requests, just to be safe.
368 [NSObject cancelPreviousPerformRequestsWithTarget:self 403 [self cancelAutoClose];
369 selector:@selector(autoClose)
370 object:nil];
371 404
372 // Schedule an autoclose after a delay. If the mouse is moved back into the 405 // Schedule an autoclose after a delay. If the mouse is moved back into the
373 // view, or if an item is added to the shelf, the timer will be canceled. 406 // view, or if an item is added to the shelf, the timer will be canceled.
374 [self performSelector:@selector(autoClose) 407 [self performSelector:@selector(autoClose)
375 withObject:nil 408 withObject:nil
376 afterDelay:kAutoCloseDelaySeconds]; 409 afterDelay:kAutoCloseDelaySeconds];
377 } 410 }
378 411
412 - (void)cancelAutoClose {
413 [NSObject cancelPreviousPerformRequestsWithTarget:self
414 selector:@selector(autoClose)
415 object:nil];
416 }
417
379 - (void)maybeAutoCloseAfterDelay { 418 - (void)maybeAutoCloseAfterDelay {
380 // We can close the shelf automatically if all the downloads on the shelf have 419 // We can close the shelf automatically if all the downloads on the shelf have
381 // been opened. 420 // been opened.
382 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) { 421 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) {
383 DownloadItemController* itemController = 422 DownloadItemController* itemController =
384 [downloadItemControllers_ objectAtIndex:i]; 423 [downloadItemControllers_ objectAtIndex:i];
385 if (![itemController download]->GetOpened()) 424 if (![itemController download]->GetOpened())
386 return; 425 return;
387 } 426 }
388 427
389 if ([self isVisible] && [downloadItemControllers_ count] > 0) { 428 if ([self isVisible] && [downloadItemControllers_ count] > 0 &&
390 // If the shelf is visible and has download items remaining on it, close the 429 isMouseInsideView_) {
391 // shelf after the user moves the mouse out of the download shelf. Note that 430 // If there are download items on the shelf and the user is potentially stil
392 // the mouse might not be over the shelf. In this case, the shelf will not 431 // interacting with them, schedule an auto close after the user moves the
393 // auto close. 432 // mouse off the shelf.
394 // TODO(asanka): Don't install a tracking area if the mouse isn't over the 433 shouldCloseOnMouseExit_ = YES;
395 // shelf. Autoclose instead.
396 [self installTrackingArea];
397 } else { 434 } else {
398 // We notify the DownloadShelf of our intention to close even if the shelf 435 // We notify the DownloadShelf of our intention to close even if the shelf
399 // is currently hidden. If the shelf was temporarily hidden (e.g. because 436 // is currently hidden. If the shelf was temporarily hidden (e.g. because
400 // the browser window entered fullscreen mode), then this prevents the shelf 437 // the browser window entered fullscreen mode), then this prevents the shelf
401 // from being shown again when the browser exits fullscreen mode. 438 // from being shown again when the browser exits fullscreen mode.
402 [self autoClose]; 439 [self autoClose];
403 } 440 }
404 } 441 }
405 442
406 - (void)autoClose { 443 - (void)autoClose {
407 bridge_->Close(DownloadShelf::AUTOMATIC); 444 bridge_->Close(DownloadShelf::AUTOMATIC);
408 } 445 }
409 446
410 - (void)installTrackingArea { 447 - (void)installTrackingArea {
411 // Install the tracking area to listen for mouseExited messages and trigger 448 // Install the tracking area to listen for mouseEntered and mouseExited
412 // the shelf autoclose. 449 // messages.
413 if (trackingArea_.get()) 450 DCHECK(!trackingArea_.get());
414 return;
415 451
416 trackingArea_.reset([[NSTrackingArea alloc] 452 trackingArea_.reset([[CrTrackingArea alloc]
417 initWithRect:[[self view] bounds] 453 initWithRect:[[self view] bounds]
418 options:NSTrackingMouseEnteredAndExited | 454 options:NSTrackingMouseEnteredAndExited |
419 NSTrackingActiveAlways | 455 NSTrackingActiveAlways |
420 NSTrackingInVisibleRect 456 NSTrackingInVisibleRect
421 owner:self 457 owner:self
422 userInfo:nil]); 458 userInfo:nil]);
423 [[self view] addTrackingArea:trackingArea_]; 459 [[self view] addTrackingArea:trackingArea_.get()];
424 } 460 }
425 461
426 - (void)cancelAutoCloseAndRemoveTrackingArea { 462 - (void)removeTrackingArea {
427 [NSObject cancelPreviousPerformRequestsWithTarget:self
428 selector:@selector(autoClose)
429 object:nil];
430
431 if (trackingArea_.get()) { 463 if (trackingArea_.get()) {
432 [[self view] removeTrackingArea:trackingArea_]; 464 [[self view] removeTrackingArea:trackingArea_.get()];
433 trackingArea_.reset(nil); 465 trackingArea_.reset(nil);
434 } 466 }
435 } 467 }
436 468
437 - (void)willEnterFullscreen { 469 - (void)willEnterFullscreen {
438 isFullscreen_ = YES; 470 isFullscreen_ = YES;
439 [self updateCloseButton]; 471 [self updateCloseButton];
440 } 472 }
441 473
442 - (void)willLeaveFullscreen { 474 - (void)willLeaveFullscreen {
(...skipping 21 matching lines...) Expand all
464 } 496 }
465 497
466 // Set the tracking off to create a new tracking area for the control. 498 // Set the tracking off to create a new tracking area for the control.
467 // When changing the bounds/frame on a HoverButton, the tracking isn't updated 499 // When changing the bounds/frame on a HoverButton, the tracking isn't updated
468 // correctly, it needs to be turned off and back on. 500 // correctly, it needs to be turned off and back on.
469 [hoverCloseButton_ setTrackingEnabled:NO]; 501 [hoverCloseButton_ setTrackingEnabled:NO];
470 [hoverCloseButton_ setFrame:bounds]; 502 [hoverCloseButton_ setFrame:bounds];
471 [hoverCloseButton_ setTrackingEnabled:YES]; 503 [hoverCloseButton_ setTrackingEnabled:YES];
472 } 504 }
473 @end 505 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698