| 
									
										
										
										
											2018-03-06 14:07:06 +09:00
										 |  |  | // Copyright (c) 2018 GitHub, Inc. | 
					
						
							|  |  |  | // Use of this source code is governed by the MIT license that can be | 
					
						
							|  |  |  | // found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "atom/browser/api/atom_api_browser_window.h" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import <Cocoa/Cocoa.h> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 15:04:40 +09:00
										 |  |  | #include "atom/browser/native_browser_view.h" | 
					
						
							| 
									
										
										
										
											2018-03-06 14:44:36 +09:00
										 |  |  | #include "atom/common/draggable_region.h" | 
					
						
							|  |  |  | #include "base/mac/scoped_nsobject.h" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 14:07:06 +09:00
										 |  |  | @interface NSView (WebContentsView) | 
					
						
							|  |  |  | - (void)setMouseDownCanMoveWindow:(BOOL)can_move; | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 14:44:36 +09:00
										 |  |  | @interface ControlRegionView : NSView | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation ControlRegionView | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (BOOL)mouseDownCanMoveWindow { | 
					
						
							|  |  |  |   return NO; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSView*)hitTest:(NSPoint)aPoint { | 
					
						
							|  |  |  |   return nil; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 14:07:06 +09:00
										 |  |  | namespace atom { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace api { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 14:44:36 +09:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Return a vector of non-draggable regions that fill a window of size | 
					
						
							|  |  |  | // |width| by |height|, but leave gaps where the window should be draggable. | 
					
						
							|  |  |  | std::vector<gfx::Rect> CalculateNonDraggableRegions( | 
					
						
							|  |  |  |     std::unique_ptr<SkRegion> draggable, int width, int height) { | 
					
						
							|  |  |  |   std::vector<gfx::Rect> result; | 
					
						
							|  |  |  |   std::unique_ptr<SkRegion> non_draggable(new SkRegion); | 
					
						
							|  |  |  |   non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op); | 
					
						
							|  |  |  |   non_draggable->op(*draggable, SkRegion::kDifference_Op); | 
					
						
							|  |  |  |   for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) { | 
					
						
							|  |  |  |     result.push_back(gfx::SkIRectToRect(it.rect())); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 14:07:06 +09:00
										 |  |  | void BrowserWindow::UpdateDraggableRegions( | 
					
						
							|  |  |  |     content::RenderFrameHost* rfh, | 
					
						
							|  |  |  |     const std::vector<DraggableRegion>& regions) { | 
					
						
							|  |  |  |   if (window_->has_frame()) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2018-03-06 14:44:36 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // All ControlRegionViews should be added as children of the WebContentsView, | 
					
						
							|  |  |  |   // because WebContentsView will be removed and re-added when entering and | 
					
						
							|  |  |  |   // leaving fullscreen mode. | 
					
						
							| 
									
										
										
										
											2018-03-06 14:07:06 +09:00
										 |  |  |   NSView* webView = web_contents()->GetNativeView(); | 
					
						
							| 
									
										
										
										
											2018-03-06 14:44:36 +09:00
										 |  |  |   NSInteger webViewWidth = NSWidth([webView bounds]); | 
					
						
							|  |  |  |   NSInteger webViewHeight = NSHeight([webView bounds]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 14:07:06 +09:00
										 |  |  |   if ([webView respondsToSelector:@selector(setMouseDownCanMoveWindow:)]) { | 
					
						
							|  |  |  |     [webView setMouseDownCanMoveWindow:YES]; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-06 14:44:36 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Remove all ControlRegionViews that are added last time. | 
					
						
							|  |  |  |   // Note that [webView subviews] returns the view's mutable internal array and | 
					
						
							|  |  |  |   // it should be copied to avoid mutating the original array while enumerating | 
					
						
							|  |  |  |   // it. | 
					
						
							|  |  |  |   base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]); | 
					
						
							|  |  |  |   for (NSView* subview in subviews.get()) | 
					
						
							|  |  |  |     if ([subview isKindOfClass:[ControlRegionView class]]) | 
					
						
							|  |  |  |       [subview removeFromSuperview]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Draggable regions is implemented by having the whole web view draggable | 
					
						
							|  |  |  |   // (mouseDownCanMoveWindow) and overlaying regions that are not draggable. | 
					
						
							|  |  |  |   draggable_regions_ = regions; | 
					
						
							|  |  |  |   std::vector<gfx::Rect> system_drag_exclude_areas; | 
					
						
							|  |  |  |   if (regions.empty()) { | 
					
						
							|  |  |  |     system_drag_exclude_areas.push_back( | 
					
						
							|  |  |  |         gfx::Rect(0, 0, webViewWidth, webViewHeight)); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     CalculateNonDraggableRegions( | 
					
						
							|  |  |  |         DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 15:04:40 +09:00
										 |  |  |   if (window_->browser_view()) | 
					
						
							|  |  |  |     window_->browser_view()->UpdateDraggableRegions(system_drag_exclude_areas); | 
					
						
							| 
									
										
										
										
											2018-03-06 14:44:36 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Create and add a ControlRegionView for each region that needs to be | 
					
						
							|  |  |  |   // excluded from the dragging. | 
					
						
							|  |  |  |   for (std::vector<gfx::Rect>::const_iterator iter = | 
					
						
							|  |  |  |            system_drag_exclude_areas.begin(); | 
					
						
							|  |  |  |        iter != system_drag_exclude_areas.end(); | 
					
						
							|  |  |  |        ++iter) { | 
					
						
							|  |  |  |     base::scoped_nsobject<NSView> controlRegion( | 
					
						
							|  |  |  |         [[ControlRegionView alloc] initWithFrame:NSZeroRect]); | 
					
						
							|  |  |  |     [controlRegion setFrame:NSMakeRect(iter->x(), | 
					
						
							|  |  |  |                                        webViewHeight - iter->bottom(), | 
					
						
							|  |  |  |                                        iter->width(), | 
					
						
							|  |  |  |                                        iter->height())]; | 
					
						
							|  |  |  |     [webView addSubview:controlRegion]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 
					
						
							|  |  |  |   // changes. Previously we tried adding an NSView and removing it, but for some | 
					
						
							|  |  |  |   // reason it required reposting the mouse-down event, and didn't always work. | 
					
						
							|  |  |  |   // Calling the below seems to be an effective solution. | 
					
						
							|  |  |  |   [[webView window] setMovableByWindowBackground:NO]; | 
					
						
							|  |  |  |   [[webView window] setMovableByWindowBackground:YES]; | 
					
						
							| 
									
										
										
										
											2018-03-06 14:07:06 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace atom |