From 9764a58efa2a722c23c4f3dbb6958e4104e06a77 Mon Sep 17 00:00:00 2001 From: Zhao Cheng Date: Tue, 9 Oct 2012 14:41:08 +0800 Subject: [PATCH] [Mac] Frameless window support. Part of fixes for #30. --- nw.gypi | 2 + src/api/api_messages.h | 11 +++++ src/api/dispatcher.cc | 22 ++++++++-- src/api/dispatcher.h | 2 +- src/common/shell_switches.cc | 1 + src/common/shell_switches.h | 1 + src/shell.cc | 14 +++++- src/shell.h | 19 ++++++++- src/shell_gtk.cc | 5 +++ src/shell_mac.mm | 82 +++++++++++++++++++++++++++++++----- src/shell_win.cc | 5 +++ tests/window/package.json | 4 +- tests/window/popup.html | 2 + 13 files changed, 151 insertions(+), 19 deletions(-) diff --git a/nw.gypi b/nw.gypi index 2e2955f724..a0076397c6 100644 --- a/nw.gypi +++ b/nw.gypi @@ -44,6 +44,8 @@ '<(DEPTH)', ], 'sources': [ + '<(DEPTH)/chrome/common/extensions/draggable_region.cc', + '<(DEPTH)/chrome/common/extensions/draggable_region.h', '<(DEPTH)/chrome/renderer/static_v8_external_string_resource.cc', '<(DEPTH)/chrome/renderer/static_v8_external_string_resource.h', 'src/api/api_messages.cc', diff --git a/src/api/api_messages.h b/src/api/api_messages.h index 615dd32714..781c8b7f89 100644 --- a/src/api/api_messages.h +++ b/src/api/api_messages.h @@ -22,11 +22,19 @@ #include #include "base/values.h" +#include "chrome/common/extensions/draggable_region.h" #include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" #define IPC_MESSAGE_START ShellMsgStart +IPC_STRUCT_TRAITS_BEGIN(extensions::DraggableRegion) + IPC_STRUCT_TRAITS_MEMBER(draggable) + IPC_STRUCT_TRAITS_MEMBER(label) + IPC_STRUCT_TRAITS_MEMBER(bounds) + IPC_STRUCT_TRAITS_MEMBER(clip) +IPC_STRUCT_TRAITS_END() + IPC_MESSAGE_ROUTED3(ShellViewHostMsg_Allocate_Object, int /* object id */, std::string /* type name */, @@ -53,3 +61,6 @@ IPC_MESSAGE_ROUTED3(ShellViewMsg_Object_On_Event, std::string /* event name */, ListValue /* arguments */) +// Sent by the renderer when the draggable regions are updated. +IPC_MESSAGE_ROUTED1(ShellViewHostMsg_UpdateDraggableRegions, + std::vector /* regions */) diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index 0eadb060dc..37a405ba52 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -23,6 +23,7 @@ #include "content/nw/src/api/api_messages.h" #include "content/public/renderer/render_view.h" #include "content/renderer/v8_value_converter_impl.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "v8/include/v8.h" @@ -36,9 +37,6 @@ Dispatcher::Dispatcher(content::RenderView* render_view) Dispatcher::~Dispatcher() { } -void Dispatcher::DidClearWindowObject(WebKit::WebFrame* frame) { -} - bool Dispatcher::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(Dispatcher, message) @@ -49,6 +47,24 @@ bool Dispatcher::OnMessageReceived(const IPC::Message& message) { return handled; } +void Dispatcher::DraggableRegionsChanged(WebKit::WebFrame* frame) { + WebKit::WebVector webregions = + frame->document().draggableRegions(); + std::vector regions; + for (size_t i = 0; i < webregions.size(); ++i) { + extensions::DraggableRegion region; + region.bounds = webregions[i].bounds; + region.draggable = webregions[i].draggable; + + // TODO(jianli): to be removed after WebKit patch that changes the draggable + // region syntax is landed. + region.label = UTF16ToASCII(webregions[i].label); + region.clip = webregions[i].clip; + + regions.push_back(region); + } + Send(new ShellViewHostMsg_UpdateDraggableRegions(routing_id(), regions)); +} void Dispatcher::OnEvent(int object_id, std::string event, diff --git a/src/api/dispatcher.h b/src/api/dispatcher.h index 5062461cb7..084ba04b3d 100644 --- a/src/api/dispatcher.h +++ b/src/api/dispatcher.h @@ -42,7 +42,7 @@ class Dispatcher : public content::RenderViewObserver { private: // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void DidClearWindowObject(WebKit::WebFrame* frame) OVERRIDE; + virtual void DraggableRegionsChanged(WebKit::WebFrame* frame) OVERRIDE; void OnEvent(int object_id, std::string event, diff --git a/src/common/shell_switches.cc b/src/common/shell_switches.cc index d067eced8e..8786752bf7 100644 --- a/src/common/shell_switches.cc +++ b/src/common/shell_switches.cc @@ -73,5 +73,6 @@ const char kmMaxWidth[] = "max_width"; const char kmMaxHeight[] = "max_height"; const char kmAsDesktop[] = "as_desktop"; const char kmFullscreen[] = "fullscreen"; +const char kmFrame[] = "frame"; } // namespace switches diff --git a/src/common/shell_switches.h b/src/common/shell_switches.h index 87acac0321..f6b7907948 100644 --- a/src/common/shell_switches.h +++ b/src/common/shell_switches.h @@ -42,6 +42,7 @@ extern const char kmMaxWidth[]; extern const char kmMaxHeight[]; extern const char kmAsDesktop[]; extern const char kmFullscreen[]; +extern const char kmFrame[]; } // namespace switches diff --git a/src/shell.cc b/src/shell.cc index 23fa94562b..a49a139ab0 100644 --- a/src/shell.cc +++ b/src/shell.cc @@ -58,6 +58,7 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) url_edit_view_(NULL), force_close_(false), id_(-1), + has_frame_(true), is_show_devtools_(false), is_toolbar_open_(true) #if defined(OS_WIN) @@ -82,6 +83,7 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) int width = 700, height = 450; manifest->GetInteger(switches::kmWidth, &width); manifest->GetInteger(switches::kmHeight, &height); + manifest->GetBoolean(switches::kmFrame, &has_frame_); PlatformCreateWindow(width, height); // Setup window from manifest. @@ -123,6 +125,7 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) // Add web contents. web_contents_.reset(web_contents); + content::WebContentsObserver::Observe(web_contents); web_contents_->SetDelegate(this); PlatformSetContents(); PlatformResizeSubViews(); @@ -256,6 +259,16 @@ gfx::NativeView Shell::GetContentView() { return web_contents_->GetNativeView(); } +bool Shell::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(Shell, message) + IPC_MESSAGE_HANDLER(ShellViewHostMsg_UpdateDraggableRegions, + UpdateDraggableRegions) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + WebContents* Shell::OpenURLFromTab(WebContents* source, const OpenURLParams& params) { // The only one we implement for now. @@ -361,7 +374,6 @@ bool Shell::AddMessageToConsole(WebContents* source, return false; } - void Shell::RequestMediaAccessPermission( content::WebContents* web_contents, const content::MediaStreamRequest* request, diff --git a/src/shell.h b/src/shell.h index 506ee52326..5b5a5739e5 100644 --- a/src/shell.h +++ b/src/shell.h @@ -30,6 +30,7 @@ #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/web_contents_delegate.h" +#include "content/public/browser/web_contents_observer.h" #include "ipc/ipc_channel.h" #include "ui/gfx/native_widget_types.h" @@ -44,6 +45,10 @@ namespace base { class DictionaryValue; } +namespace extensions { +struct DraggableRegion; +} + namespace nw { class Package; } @@ -60,6 +65,7 @@ class WebContents; // This represents one window of the Content Shell, i.e. all the UI including // buttons and url bar, as well as the web content area. class Shell : public WebContentsDelegate, + public content::WebContentsObserver, public NotificationObserver { public: virtual ~Shell(); @@ -90,6 +96,9 @@ class Shell : public WebContentsDelegate, void SetAsDesktop(); #endif + void UpdateDraggableRegions( + const std::vector& regions); + // Send an event to renderer. void SendEvent(const std::string& event); @@ -116,6 +125,8 @@ class Shell : public WebContentsDelegate, static nw::Package* GetPackage(); + gfx::NativeView GetContentView(); + WebContents* web_contents() const { return web_contents_.get(); } gfx::NativeWindow window() { return window_; } @@ -129,6 +140,9 @@ class Shell : public WebContentsDelegate, void URLEntered(std::string url_string); #endif + // content::WebContentsObserver implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + // WebContentsDelegate virtual WebContents* OpenURLFromTab(WebContents* source, const OpenURLParams& params) OVERRIDE; @@ -196,8 +210,6 @@ class Shell : public WebContentsDelegate, // Sets whether the spinner is spinning. void PlatformSetIsLoading(bool loading); - gfx::NativeView GetContentView(); - // NotificationObserver virtual void Observe(int type, const NotificationSource& source, @@ -238,6 +250,9 @@ class Shell : public WebContentsDelegate, // ID of corresponding js object. int id_; + // Is it a frameless window? + bool has_frame_; + // Debug settings. bool is_show_devtools_; bool is_toolbar_open_; diff --git a/src/shell_gtk.cc b/src/shell_gtk.cc index 8cc09a2531..16a440180e 100644 --- a/src/shell_gtk.cc +++ b/src/shell_gtk.cc @@ -171,6 +171,11 @@ void Shell::SetAsDesktop() { gdk_screen_get_height(screen)); } +void Shell::UpdateDraggableRegions( + const std::vector& regions) { + LOG(ERROR) << "UpdateDraggableRegions"; +} + void Shell::PlatformInitialize() { } diff --git a/src/shell_mac.mm b/src/shell_mac.mm index b0648e03c7..23e8ca8150 100644 --- a/src/shell_mac.mm +++ b/src/shell_mac.mm @@ -29,6 +29,7 @@ #include "base/string_piece.h" #include "base/sys_string_conversions.h" #include "base/values.h" +#include "chrome/common/extensions/draggable_region.h" #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" @@ -153,6 +154,21 @@ - (void)showDevTools:(id)sender { @end +@interface ControlRegionView : NSView +@end +@implementation ControlRegionView +- (BOOL)mouseDownCanMoveWindow { + return NO; +} +- (NSView*)hitTest:(NSPoint)aPoint { + return nil; +} +@end + +@interface NSView (WebContentsView) +- (void)setMouseDownCanMoveWindow:(BOOL)can_move; +@end + namespace { // Layout constants (in view coordinates) @@ -272,6 +288,42 @@ void MakeShellButton(NSRect* rect, [window_ setTitle:title_string]; } +void Shell::UpdateDraggableRegions( + const std::vector& regions) { + if (has_frame_) + return; + + // All ControlRegionViews should be added as children of the WebContentsView, + // because WebContentsView will be removed and re-added when entering and + // leaving fullscreen mode. + NSView* webView = web_contents()->GetView()->GetNativeView(); + NSInteger webViewHeight = NSHeight([webView bounds]); + + // 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. + scoped_nsobject subviews([[webView subviews] copy]); + for (NSView* subview in subviews.get()) + if ([subview isKindOfClass:[ControlRegionView class]]) + [subview removeFromSuperview]; + + // Create and add ControlRegionView for each region that needs to be excluded + // from the dragging. + for (std::vector::const_iterator iter = + regions.begin(); + iter != regions.end(); + ++iter) { + const extensions::DraggableRegion& region = *iter; + scoped_nsobject controlRegion([[ControlRegionView alloc] init]); + [controlRegion setFrame:NSMakeRect(region.bounds.x(), + webViewHeight - region.bounds.bottom(), + region.bounds.width(), + region.bounds.height())]; + [webView addSubview:controlRegion]; + } +} + void Shell::PlatformInitialize() { } @@ -313,14 +365,15 @@ void MakeShellButton(NSRect* rect, NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | - NSResizableWindowMask; + NSResizableWindowMask | + NSTexturedBackgroundWindowMask; CrShellWindow* window = [[CrShellWindow alloc] initWithContentRect:content_rect styleMask:style_mask backing:NSBackingStoreBuffered defer:NO]; - window_ = window; [window setShell:this]; + window_ = window; NSView* content = [window_ contentView]; // Set the shell window to participate in Lion Fullscreen mode. Set @@ -407,17 +460,24 @@ void MakeShellButton(NSRect* rect, } void Shell::PlatformSetContents() { - NSView* web_view = web_contents_->GetView()->GetNativeView(); - NSView* content = [window_ contentView]; - [content addSubview:web_view]; + NSView* view = web_contents()->GetView()->GetNativeView(); + if (has_frame_) { + NSRect frame = [[window() contentView] bounds]; + if (is_toolbar_open_) + frame.size.height -= kURLBarHeight; + [view setFrame:frame]; + [[window() contentView] addSubview:view]; + } else { + [view setMouseDownCanMoveWindow:YES]; - NSRect frame = [content bounds]; - if (is_toolbar_open_) { - frame.size.height -= kURLBarHeight; + NSView* frameView = [[window() contentView] superview]; + [view setFrame:[frameView bounds]]; + [frameView addSubview:view]; + + [[window() standardWindowButton:NSWindowZoomButton] setHidden:YES]; + [[window() standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; + [[window() standardWindowButton:NSWindowCloseButton] setHidden:YES]; } - [web_view setFrame:frame]; - [web_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; - [web_view setNeedsDisplay:YES]; } void Shell::PlatformResizeSubViews() { diff --git a/src/shell_win.cc b/src/shell_win.cc index c12398db68..adb72cc979 100644 --- a/src/shell_win.cc +++ b/src/shell_win.cc @@ -132,6 +132,11 @@ void Shell::SetTitle(const std::string& title) { ::SetWindowText(window_, title_utf16.c_str()); } +void Shell::UpdateDraggableRegions( + const std::vector& regions) { + LOG(ERROR) << "UpdateDraggableRegions"; +} + void Shell::PlatformInitialize() { _setmode(_fileno(stdout), _O_BINARY); _setmode(_fileno(stderr), _O_BINARY); diff --git a/tests/window/package.json b/tests/window/package.json index 24371b97a1..766e0317d9 100644 --- a/tests/window/package.json +++ b/tests/window/package.json @@ -3,9 +3,11 @@ "main": "index.html", "window": { "title": "Window Test", + "toolbar": false, "position": "center", "width": 400, "height": 500, - "resizable": false + "resizable": false, + "frame": false } } diff --git a/tests/window/popup.html b/tests/window/popup.html index a1244a99e8..70f392c528 100644 --- a/tests/window/popup.html +++ b/tests/window/popup.html @@ -4,6 +4,8 @@ New Window +
+
This is the popup window