diff options
19 files changed, 294 insertions, 96 deletions
diff --git a/chrome/browser/extensions/api/tabs/tabs.cc b/chrome/browser/extensions/api/tabs/tabs.cc index ef2f8d1..cfd913c 100644 --- a/chrome/browser/extensions/api/tabs/tabs.cc +++ b/chrome/browser/extensions/api/tabs/tabs.cc @@ -459,31 +459,13 @@ bool CreateWindowFunction::RunImpl() { } } - // Try to position the new browser relative its originating browser window. - gfx::Rect window_bounds; - // The call offsets the bounds by kWindowTilePixels (defined in WindowSizer to - // be 10) - // - // NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here. - // GetBrowserWindowBounds will default to saved "default" values for the app. - WindowSizer::GetBrowserWindowBounds(std::string(), gfx::Rect(), - GetCurrentBrowser(), &window_bounds); - - // Calculate popup and panels bounds separately. - gfx::Rect popup_bounds; - gfx::Rect panel_bounds; // Use 0x0 for panels. Panel manager sizes them. - - // In ChromiumOS the default popup bounds is 0x0 which indicates default - // window sizes in PanelBrowserView. In other OSs use the same default - // bounds as windows. -#if defined(OS_CHROMEOS) - popup_bounds = panel_bounds; -#else - popup_bounds = window_bounds; // Use window size as default for popups -#endif - Profile* window_profile = profile(); Browser::Type window_type = Browser::TYPE_TABBED; + + // panel_create_mode only applies if window is TYPE_PANEL. + PanelManager::CreateMode panel_create_mode = PanelManager::CREATE_AS_DOCKED; + + gfx::Rect window_bounds; bool focused = true; bool saw_focus_key = false; std::string extension_id; @@ -501,38 +483,89 @@ bool CreateWindowFunction::RunImpl() { } if (args) { + // Figure out window type before figuring out bounds so that default + // bounds can be set according to the window type. + std::string type_str; + if (args->HasKey(keys::kWindowTypeKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kWindowTypeKey, + &type_str)); + if (type_str == keys::kWindowTypeValuePopup) { + window_type = Browser::TYPE_POPUP; + extension_id = GetExtension()->id(); + } else if (type_str == keys::kWindowTypeValuePanel || + type_str == keys::kWindowTypeValueDetachedPanel) { + extension_id = GetExtension()->id(); + bool use_panels = false; +#if !defined(OS_ANDROID) + use_panels = PanelManager::ShouldUsePanels(extension_id); +#endif + if (use_panels) { + window_type = Browser::TYPE_PANEL; + if (type_str == keys::kWindowTypeValueDetachedPanel) + panel_create_mode = PanelManager::CREATE_AS_DETACHED; + } else { + window_type = Browser::TYPE_POPUP; + } + } else if (type_str != keys::kWindowTypeValueNormal) { + error_ = keys::kInvalidWindowTypeError; + return false; + } + } + + // Initialize default window bounds according to window type. + // In ChromiumOS the default popup bounds is 0x0 which indicates default + // window sizes in PanelBrowserView. In other OSs use the same default + // bounds as windows. +#if !defined(OS_CHROMEOS) + if (Browser::TYPE_TABBED == window_type || + Browser::TYPE_POPUP == window_type) { +#else + if (Browser::TYPE_TABBED == window_type) { +#endif + // Try to position the new browser relative to its originating + // browser window. The call offsets the bounds by kWindowTilePixels + // (defined in WindowSizer to be 10). + // + // NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here. + // GetBrowserWindowBounds will default to saved "default" values for + // the app. + WindowSizer::GetBrowserWindowBounds(std::string(), gfx::Rect(), + GetCurrentBrowser(), + &window_bounds); + } + +#if !defined(USE_ASH) + if (Browser::TYPE_PANEL == window_type && + PanelManager::CREATE_AS_DETACHED == panel_create_mode) { + window_bounds.set_origin( + PanelManager::GetInstance()->GetDefaultDetachedPanelOrigin()); + } +#endif + // Any part of the bounds can optionally be set by the caller. int bounds_val = -1; if (args->HasKey(keys::kLeftKey)) { EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kLeftKey, &bounds_val)); window_bounds.set_x(bounds_val); - popup_bounds.set_x(bounds_val); - panel_bounds.set_x(bounds_val); } if (args->HasKey(keys::kTopKey)) { EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kTopKey, &bounds_val)); window_bounds.set_y(bounds_val); - popup_bounds.set_y(bounds_val); - panel_bounds.set_y(bounds_val); } if (args->HasKey(keys::kWidthKey)) { EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kWidthKey, &bounds_val)); window_bounds.set_width(bounds_val); - popup_bounds.set_width(bounds_val); - panel_bounds.set_width(bounds_val); } if (args->HasKey(keys::kHeightKey)) { EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kHeightKey, &bounds_val)); window_bounds.set_height(bounds_val); - popup_bounds.set_height(bounds_val); - panel_bounds.set_height(bounds_val); } if (args->HasKey(keys::kFocusedKey)) { @@ -540,54 +573,30 @@ bool CreateWindowFunction::RunImpl() { &focused)); saw_focus_key = true; } - - std::string type_str; - if (args->HasKey(keys::kWindowTypeKey)) { - EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kWindowTypeKey, - &type_str)); - if (type_str == keys::kWindowTypeValuePopup) { - window_type = Browser::TYPE_POPUP; - extension_id = GetExtension()->id(); - } else if (type_str == keys::kWindowTypeValuePanel) { - extension_id = GetExtension()->id(); - bool use_panels = false; -#if !defined(OS_ANDROID) - use_panels = PanelManager::ShouldUsePanels(extension_id); -#endif - if (use_panels) - window_type = Browser::TYPE_PANEL; - else - window_type = Browser::TYPE_POPUP; - } else if (type_str != keys::kWindowTypeValueNormal) { - error_ = keys::kInvalidWindowTypeError; - return false; - } - } } - if (window_type == Browser::TYPE_PANEL) { +#if !defined(USE_ASH) + if (window_type == Browser::TYPE_PANEL && + PanelManager::UseBrowserlessPanels()) { std::string title = web_app::GenerateApplicationNameFromExtensionId(extension_id); -#if !defined(USE_ASH) - if (PanelManager::UseBrowserlessPanels()) { - // Note: Panels ignore all but the first url provided. - Panel* panel = PanelManager::GetInstance()->CreatePanel( - title, window_profile, urls[0], panel_bounds.size()); + // Note: Panels ignore all but the first url provided. + Panel* panel = PanelManager::GetInstance()->CreatePanel( + title, window_profile, urls[0], window_bounds, panel_create_mode); - // Unlike other window types, Panels do not take focus by default. - if (!saw_focus_key || !focused) - panel->ShowInactive(); - else - panel->Show(); + // Unlike other window types, Panels do not take focus by default. + if (!saw_focus_key || !focused) + panel->ShowInactive(); + else + panel->Show(); SetResult( panel->extension_window_controller()->CreateWindowValueWithTabs( GetExtension())); return true; } + // else fall through to create BrowserWindow #endif - // else fall through to create BrowserWindow - } // Create a new BrowserWindow. Browser::CreateParams create_params(window_type, window_profile); @@ -597,7 +606,7 @@ bool CreateWindowFunction::RunImpl() { create_params = Browser::CreateParams::CreateForApp( window_type, web_app::GenerateApplicationNameFromExtensionId(extension_id), - (window_type == Browser::TYPE_PANEL ? panel_bounds : popup_bounds), + window_bounds, window_profile); } create_params.initial_show_state = ui::SHOW_STATE_NORMAL; diff --git a/chrome/browser/extensions/api/tabs/tabs_constants.cc b/chrome/browser/extensions/api/tabs/tabs_constants.cc index 10fd9e9..27c2aab 100644 --- a/chrome/browser/extensions/api/tabs/tabs_constants.cc +++ b/chrome/browser/extensions/api/tabs/tabs_constants.cc @@ -67,6 +67,7 @@ const char kStatusValueLoading[] = "loading"; const char kWindowTypeValueNormal[] = "normal"; const char kWindowTypeValuePopup[] = "popup"; const char kWindowTypeValuePanel[] = "panel"; +const char kWindowTypeValueDetachedPanel[] = "detached_panel"; const char kWindowTypeValueApp[] = "app"; const char kCanOnlyMoveTabsWithinNormalWindowsError[] = "Tabs can only be " diff --git a/chrome/browser/extensions/api/tabs/tabs_constants.h b/chrome/browser/extensions/api/tabs/tabs_constants.h index 50bcebd..6ac0b93 100644 --- a/chrome/browser/extensions/api/tabs/tabs_constants.h +++ b/chrome/browser/extensions/api/tabs/tabs_constants.h @@ -71,6 +71,7 @@ extern const char kStatusValueLoading[]; extern const char kWindowTypeValueNormal[]; extern const char kWindowTypeValuePopup[]; extern const char kWindowTypeValuePanel[]; +extern const char kWindowTypeValueDetachedPanel[]; extern const char kWindowTypeValueApp[]; // Error messages. diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc index 7e29c72..a84cbe98 100644 --- a/chrome/browser/extensions/window_open_apitest.cc +++ b/chrome/browser/extensions/window_open_apitest.cc @@ -213,6 +213,19 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanel) { ASSERT_TRUE(RunExtensionTest("window_open/panel")) << message_; } +#if defined(USE_ASH) +// On Ash, this currently fails because we're currently opening new panel +// windows as popup windows instead. +#define MAYBE_WindowOpenPanelDetached FAILS_WindowOpenPanelDetached +#else +#define MAYBE_WindowOpenPanelDetached WindowOpenPanelDetached +#endif +IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanelDetached) { + if (!PanelManager::UseBrowserlessPanels()) + return; + ASSERT_TRUE(RunExtensionTest("window_open/panel_detached")) << message_; +} + #if defined(OS_MACOSX) || defined(OS_WIN) // Focus test fails if there is no window manager on Linux. IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, WindowOpenFocus) { diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc index 483ca65..6ecf4c9 100644 --- a/chrome/browser/task_manager/task_manager_browsertest.cc +++ b/chrome/browser/task_manager/task_manager_browsertest.cc @@ -151,7 +151,8 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_NoticePanelChanges) { last_loaded_extension_id_), browser()->profile(), url, - gfx::Size(300, 400)); + gfx::Rect(300, 400), + PanelManager::CREATE_AS_DOCKED); TaskManagerBrowserTestUtil::WaitForResourceChange(4); // Check that the fourth entry is a resource with the panel's web contents diff --git a/chrome/browser/ui/panels/base_panel_browser_test.cc b/chrome/browser/ui/panels/base_panel_browser_test.cc index 2aae355..d127f7b 100644 --- a/chrome/browser/ui/panels/base_panel_browser_test.cc +++ b/chrome/browser/ui/panels/base_panel_browser_test.cc @@ -15,8 +15,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/panels/native_panel.h" -#include "chrome/browser/ui/panels/panel_manager.h" #include "chrome/browser/ui/panels/panel_mouse_watcher.h" +#include "chrome/browser/ui/panels/panel_strip.h" #include "chrome/browser/ui/panels/test_panel_active_state_observer.h" #include "chrome/browser/ui/panels/test_panel_mouse_watcher.h" #include "chrome/browser/ui/tab_contents/tab_contents.h" @@ -291,7 +291,8 @@ BasePanelBrowserTest::CreatePanelParams::CreatePanelParams( bounds(bounds), show_flag(show_flag), wait_for_fully_created(true), - expected_active_state(show_flag) { + expected_active_state(show_flag), + create_mode(PanelManager::CREATE_AS_DOCKED) { } Panel* BasePanelBrowserTest::CreatePanelWithParams( @@ -312,7 +313,8 @@ Panel* BasePanelBrowserTest::CreatePanelWithParams( PanelManager* manager = PanelManager::GetInstance(); Panel* panel = manager->CreatePanel(params.name, browser()->profile(), - params.url, params.bounds.size()); + params.url, params.bounds, + params.create_mode); if (!params.url.is_empty()) observer.Wait(); diff --git a/chrome/browser/ui/panels/base_panel_browser_test.h b/chrome/browser/ui/panels/base_panel_browser_test.h index 1a1cbdf..425e16c 100644 --- a/chrome/browser/ui/panels/base_panel_browser_test.h +++ b/chrome/browser/ui/panels/base_panel_browser_test.h @@ -9,7 +9,7 @@ #include "base/memory/ref_counted.h" #include "chrome/browser/ui/panels/display_settings_provider.h" #include "chrome/browser/ui/panels/panel.h" -#include "chrome/browser/ui/panels/panel_strip.h" +#include "chrome/browser/ui/panels/panel_manager.h" #include "chrome/common/extensions/extension.h" #include "chrome/test/base/in_process_browser_test.h" #include "ui/gfx/rect.h" @@ -63,6 +63,7 @@ class BasePanelBrowserTest : public InProcessBrowserTest { GURL url; bool wait_for_fully_created; ActiveState expected_active_state; + PanelManager::CreateMode create_mode; CreatePanelParams(const std::string& name, const gfx::Rect& bounds, diff --git a/chrome/browser/ui/panels/detached_panel_browsertest.cc b/chrome/browser/ui/panels/detached_panel_browsertest.cc index cc4858e..fa43795 100644 --- a/chrome/browser/ui/panels/detached_panel_browsertest.cc +++ b/chrome/browser/ui/panels/detached_panel_browsertest.cc @@ -16,13 +16,19 @@ IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, CheckDetachedPanelProperties) { PanelManager* panel_manager = PanelManager::GetInstance(); DetachedPanelStrip* detached_strip = panel_manager->detached_strip(); - Panel* panel = CreateDetachedPanel("1", gfx::Rect(300, 200, 250, 200)); + // Create an initially detached panel (as opposed to other tests which create + // a docked panel, then detaches it). + gfx::Rect bounds(300, 200, 250, 200); + CreatePanelParams params("1", bounds, SHOW_AS_ACTIVE); + params.create_mode = PanelManager::CREATE_AS_DETACHED; + Panel* panel = CreatePanelWithParams(params); scoped_ptr<NativePanelTesting> panel_testing( CreateNativePanelTesting(panel)); EXPECT_EQ(1, panel_manager->num_panels()); EXPECT_TRUE(detached_strip->HasPanel(panel)); + EXPECT_EQ(bounds, panel->GetBounds()); EXPECT_FALSE(panel->always_on_top()); EXPECT_TRUE(panel_testing->IsButtonVisible(panel::CLOSE_BUTTON)); diff --git a/chrome/browser/ui/panels/detached_panel_strip.cc b/chrome/browser/ui/panels/detached_panel_strip.cc index b3c6394..c9f59e5 100644 --- a/chrome/browser/ui/panels/detached_panel_strip.cc +++ b/chrome/browser/ui/panels/detached_panel_strip.cc @@ -9,6 +9,12 @@ #include "chrome/browser/ui/panels/panel_drag_controller.h" #include "chrome/browser/ui/panels/panel_manager.h" +namespace { +// How much horizontal and vertical offset there is between newly opened +// detached panels. +const int kPanelTilePixels = 10; +} // namespace + DetachedPanelStrip::DetachedPanelStrip(PanelManager* panel_manager) : PanelStrip(PanelStrip::DETACHED), panel_manager_(panel_manager) { @@ -66,6 +72,11 @@ void DetachedPanelStrip::AddPanel(Panel* panel, DCHECK_NE(this, panel->panel_strip()); panel->set_panel_strip(this); panels_.insert(panel); + + // Offset the default position of the next detached panel if the current + // default position is used. + if (panel->GetBounds().origin() == default_panel_origin_) + ComputeNextDefaultPanelOrigin(); } void DetachedPanelStrip::RemovePanel(Panel* panel) { @@ -228,3 +239,22 @@ void DetachedPanelStrip::UpdatePanelOnStripChange(Panel* panel) { void DetachedPanelStrip::OnPanelActiveStateChanged(Panel* panel) { } +gfx::Point DetachedPanelStrip::GetDefaultPanelOrigin() { + if (!default_panel_origin_.x() && !default_panel_origin_.y()) { + gfx::Rect display_area = + panel_manager_->display_settings_provider()->GetDisplayArea(); + default_panel_origin_.SetPoint(kPanelTilePixels + display_area.x(), + kPanelTilePixels + display_area.y()); + } + return default_panel_origin_; +} + +void DetachedPanelStrip::ComputeNextDefaultPanelOrigin() { + default_panel_origin_.Offset(kPanelTilePixels, kPanelTilePixels); + gfx::Rect display_area = + panel_manager_->display_settings_provider()->GetDisplayArea(); + if (!display_area.Contains(default_panel_origin_)) { + default_panel_origin_.SetPoint(kPanelTilePixels + display_area.x(), + kPanelTilePixels + display_area.y()); + } +} diff --git a/chrome/browser/ui/panels/detached_panel_strip.h b/chrome/browser/ui/panels/detached_panel_strip.h index 51fd2a2..d7560f9 100644 --- a/chrome/browser/ui/panels/detached_panel_strip.h +++ b/chrome/browser/ui/panels/detached_panel_strip.h @@ -65,7 +65,15 @@ class DetachedPanelStrip : public PanelStrip { int num_panels() const { return panels_.size(); } const Panels& panels() const { return panels_; } + // Returns default top-left to use for a detached panel whose position is + // not specified during panel creation. + gfx::Point GetDefaultPanelOrigin(); + private: + // Offset the default panel top-left position by kPanelTilePixels. Wrap + // around to initial position if position goes beyond display area. + void ComputeNextDefaultPanelOrigin(); + struct PanelPlacement { Panel* panel; gfx::Point position; @@ -84,6 +92,10 @@ class DetachedPanelStrip : public PanelStrip { // Used to save the placement information for a panel. PanelPlacement saved_panel_placement_; + // Default top-left position to use for next detached panel if position is + // unspecified by panel creator. + gfx::Point default_panel_origin_; + DISALLOW_COPY_AND_ASSIGN(DetachedPanelStrip); }; diff --git a/chrome/browser/ui/panels/panel_cocoa_unittest.mm b/chrome/browser/ui/panels/panel_cocoa_unittest.mm index 89b4f5f..700d369 100644 --- a/chrome/browser/ui/panels/panel_cocoa_unittest.mm +++ b/chrome/browser/ui/panels/panel_cocoa_unittest.mm @@ -52,7 +52,8 @@ class PanelCocoaTest : public CocoaProfileTest { int panels_count = manager->num_panels(); Panel* panel = manager->CreatePanel(panel_name, profile(), - GURL(), gfx::Size()); + GURL(), gfx::Rect(), + PanelManager::CREATE_AS_DOCKED); EXPECT_EQ(panels_count + 1, manager->num_panels()); EXPECT_TRUE(panel); diff --git a/chrome/browser/ui/panels/panel_manager.cc b/chrome/browser/ui/panels/panel_manager.cc index bc95b68..1e81f28 100644 --- a/chrome/browser/ui/panels/panel_manager.cc +++ b/chrome/browser/ui/panels/panel_manager.cc @@ -129,6 +129,10 @@ PanelManager::~PanelManager() { docked_strip_.reset(); } +gfx::Point PanelManager::GetDefaultDetachedPanelOrigin() { + return detached_strip_->GetDefaultPanelOrigin(); +} + void PanelManager::OnDisplayAreaChanged(const gfx::Rect& display_area) { if (display_area == display_area_) return; @@ -157,21 +161,23 @@ int PanelManager::GetMaxPanelHeight() const { Panel* PanelManager::CreatePanel(Browser* browser) { return CreatePanel(browser, "", NULL, GURL(), - browser->override_bounds().size()); + browser->override_bounds(), CREATE_AS_DOCKED); } Panel* PanelManager::CreatePanel(const std::string& app_name, Profile* profile, const GURL& url, - const gfx::Size& requested_size) { - return CreatePanel(NULL, app_name, profile, url, requested_size); + const gfx::Rect& requested_bounds, + CreateMode mode) { + return CreatePanel(NULL, app_name, profile, url, requested_bounds, mode); } Panel* PanelManager::CreatePanel(Browser* browser, const std::string& app_name, Profile* profile, const GURL& url, - const gfx::Size& requested_size) { + const gfx::Rect& requested_bounds, + CreateMode mode) { // Need to sync the display area if no panel is present. This is because: // 1) Display area is not initialized until first panel is created. // 2) On windows, display settings notification is tied to a window. When @@ -183,8 +189,8 @@ Panel* PanelManager::CreatePanel(Browser* browser, } // Compute initial bounds for the panel. - int width = requested_size.width(); - int height = requested_size.height(); + int width = requested_bounds.width(); + int height = requested_bounds.height(); if (width == 0) width = height * kPanelDefaultWidthToHeightRatio; else if (height == 0) @@ -202,9 +208,13 @@ Panel* PanelManager::CreatePanel(Browser* browser, else if (height > max_size.height()) height = max_size.height(); - gfx::Size panel_size(width, height); - gfx::Rect bounds(docked_strip_->GetDefaultPositionForPanel(panel_size), - panel_size); + gfx::Rect bounds(width, height); + if (CREATE_AS_DOCKED == mode) { + bounds.set_origin(docked_strip_->GetDefaultPositionForPanel(bounds.size())); + } else { + bounds.set_origin(requested_bounds.origin()); + bounds = bounds.AdjustToFit(display_settings_provider_->GetDisplayArea()); + } // Create the panel. Panel* panel; @@ -218,17 +228,27 @@ Panel* PanelManager::CreatePanel(Browser* browser, } // Auto resizable feature is enabled only if no initial size is requested. - if (auto_sizing_enabled() && requested_size.width() == 0 && - requested_size.height() == 0) { + if (auto_sizing_enabled() && requested_bounds.width() == 0 && + requested_bounds.height() == 0) { panel->SetAutoResizable(true); } - // Add the panel to the docked strip. + // Add the panel to the appropriate panel strip. // Delay layout refreshes in case multiple panels are created within // a short time of one another or the focus changes shortly after panel // is created to avoid excessive screen redraws. - docked_strip_->AddPanel(panel, PanelStrip::DELAY_LAYOUT_REFRESH); - docked_strip_->UpdatePanelOnStripChange(panel); + PanelStrip* panel_strip; + PanelStrip::PositioningMask positioning_mask; + if (CREATE_AS_DOCKED == mode) { + panel_strip = docked_strip_.get(); + positioning_mask = PanelStrip::DELAY_LAYOUT_REFRESH; + } else { + panel_strip = detached_strip_.get(); + positioning_mask = PanelStrip::KNOWN_POSITION; + } + + panel_strip->AddPanel(panel, positioning_mask); + panel_strip->UpdatePanelOnStripChange(panel); return panel; } diff --git a/chrome/browser/ui/panels/panel_manager.h b/chrome/browser/ui/panels/panel_manager.h index 45067c4..24c2a9a 100644 --- a/chrome/browser/ui/panels/panel_manager.h +++ b/chrome/browser/ui/panels/panel_manager.h @@ -28,6 +28,11 @@ class PanelMouseWatcher; class PanelManager : public DisplaySettingsProvider::DisplayAreaObserver, public DisplaySettingsProvider::FullScreenObserver { public: + enum CreateMode { + CREATE_AS_DOCKED, // Creates a docked panel. The default. + CREATE_AS_DETACHED // Creates a detached panel. + }; + // Returns a single instance. static PanelManager* GetInstance(); @@ -38,17 +43,22 @@ class PanelManager : public DisplaySettingsProvider::DisplayAreaObserver, // TODO(jennb): Delete after refactor. static bool UseBrowserlessPanels(); + // Returns the default top-left position for a detached panel. + gfx::Point GetDefaultDetachedPanelOrigin(); + // Creates a panel and returns it. The panel might be queued for display // later. // |app_name| is the default title for Panels when the page content does not // provide a title. For extensions, this is usually the application name // generated from the extension id. - // |requested_size| is the desired size for the panel, but actual - // size may differ after panel layout. + // |requested_bounds| is the desired bounds for the panel, but actual + // bounds may differ after panel layout depending on create |mode|. + // |mode| indicates whether panel should be created as docked or detached. Panel* CreatePanel(const std::string& app_name, Profile* profile, const GURL& url, - const gfx::Size& requested_size); + const gfx::Rect& requested_bounds, + CreateMode mode); Panel* CreatePanel(Browser* browser); // legacy // Close all panels (asynchronous). Panels will be removed after closing. @@ -173,7 +183,8 @@ class PanelManager : public DisplaySettingsProvider::DisplayAreaObserver, const std::string& app_name, Profile* profile, const GURL& url, - const gfx::Size& requested_size); + const gfx::Rect& requested_bounds, + CreateMode mode); // Overridden from DisplaySettingsProvider::DisplayAreaObserver: virtual void OnDisplayAreaChanged(const gfx::Rect& display_area) OVERRIDE; diff --git a/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm b/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm index 000eb96..f2dc5c3 100644 --- a/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm +++ b/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm @@ -326,7 +326,8 @@ static NSEvent* MakeMouseEvent(NSEventType type, hoverImage:rb.GetNativeImageNamed(IDR_PANEL_RESTORE_H) pressedImage:rb.GetNativeImageNamed(IDR_PANEL_RESTORE_C) toolTip:l10n_util::GetNSStringWithFixup(IDS_PANEL_RESTORE_TOOLTIP)]; - [restoreButton_ setHidden:YES]; // Only visible when panel is minimized. + + [controller_ updateTitleBarMinimizeRestoreButtonVisibility]; [self updateCustomButtonsLayout]; diff --git a/chrome/browser/ui/panels/panel_view.cc b/chrome/browser/ui/panels/panel_view.cc index b18d0fc..2509b8f 100644 --- a/chrome/browser/ui/panels/panel_view.cc +++ b/chrome/browser/ui/panels/panel_view.cc @@ -161,6 +161,7 @@ NativePanel* Panel::CreateNativePanel(Panel* panel, const gfx::Rect& bounds) { PanelView::PanelView(Panel* panel, const gfx::Rect& bounds) : panel_(panel), + bounds_(bounds), window_(NULL), web_view_(NULL), focused_(false), diff --git a/chrome/common/extensions/api/windows.json b/chrome/common/extensions/api/windows.json index 9e3cd85..dbfe080 100644 --- a/chrome/common/extensions/api/windows.json +++ b/chrome/common/extensions/api/windows.json @@ -173,8 +173,8 @@ "type": { "type": "string", "optional": true, - "description": "Specifies what type of browser window to create. The 'panel' type creates a popup unless the '--enable-panels' flag is set.", - "enum": ["normal", "popup", "panel"] + "description": "Specifies what type of browser window to create. The 'panel' and 'detached_panel' types create a popup unless the '--enable-panels' flag is set.", + "enum": ["normal", "popup", "panel", "detached_panel"] } }, "optional": true diff --git a/chrome/test/data/extensions/api_test/window_open/panel_detached/manifest.json b/chrome/test/data/extensions/api_test/window_open/panel_detached/manifest.json new file mode 100644 index 0000000..be043e6 --- /dev/null +++ b/chrome/test/data/extensions/api_test/window_open/panel_detached/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "window/create.detached-panel", + "version": "0.1", + "manifest_version": 2, + "description": "Tests window.create with detached_panel type.", + "background": { + "page": "test.html" + }, + "permissions": ["tabs"] +} diff --git a/chrome/test/data/extensions/api_test/window_open/panel_detached/test.html b/chrome/test/data/extensions/api_test/window_open/panel_detached/test.html new file mode 100644 index 0000000..78a21b8 --- /dev/null +++ b/chrome/test/data/extensions/api_test/window_open/panel_detached/test.html @@ -0,0 +1,6 @@ +<!-- + * Copyright (c) 2012 The Chromium Authors. All rights reserved. Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<script src="test.js"></script> diff --git a/chrome/test/data/extensions/api_test/window_open/panel_detached/test.js b/chrome/test/data/extensions/api_test/window_open/panel_detached/test.js new file mode 100644 index 0000000..34d8c42 --- /dev/null +++ b/chrome/test/data/extensions/api_test/window_open/panel_detached/test.js @@ -0,0 +1,72 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function createCallback(win) { + chrome.test.assertEq('panel', win.type); + // Unlike docked panels, detached is not alwaysOnTop. + chrome.test.assertEq(false, win.alwaysOnTop); +} + +chrome.test.runTests([ + // No origin nor size is specified. + function openDetachedPanel() { + chrome.test.listenOnce(chrome.windows.onCreated, function(window) { + chrome.test.assertEq("panel", window.type); + chrome.test.assertTrue(!window.incognito); + chrome.test.assertTrue(window.width > 0); + chrome.test.assertTrue(window.height > 0); + }); + chrome.windows.create( + { 'url': 'about:blank', + 'type': 'detached_panel' }, + chrome.test.callbackPass(createCallback)); + }, + + // Verify supplied size is obeyed even if no origin is specified. + function openDetachedPanelWithSize() { + chrome.test.listenOnce(chrome.windows.onCreated, function(window) { + chrome.test.assertEq("panel", window.type); + chrome.test.assertTrue(!window.incognito); + chrome.test.assertEq(250, window.width); + chrome.test.assertEq(300, window.height); + }); + chrome.windows.create( + { 'url': 'about:blank', + 'type': 'detached_panel', 'width': 250, 'height': 300 }, + chrome.test.callbackPass(createCallback)); + }, + + // Verify supplied origin is obeyed even if no size is specified. + function openDetachedPanelWithOrigin() { + chrome.test.listenOnce(chrome.windows.onCreated, function(window) { + chrome.test.assertEq("panel", window.type); + chrome.test.assertTrue(!window.incognito); + chrome.test.assertEq(42, window.top); + chrome.test.assertEq(24, window.left); + chrome.test.assertTrue(window.width > 0); + chrome.test.assertTrue(window.height > 0); + }); + chrome.windows.create( + { 'url': 'about:blank', + 'type': 'detached_panel', 'top': 42, 'left': 24 }, + chrome.test.callbackPass(createCallback)); + }, + + // Verify supplied bounds are obeyed. + function openDetachedPanelWithFullBounds() { + chrome.test.listenOnce(chrome.windows.onCreated, function(window) { + chrome.test.assertEq("panel", window.type); + chrome.test.assertTrue(!window.incognito); + chrome.test.assertEq(42, window.top); + chrome.test.assertEq(24, window.left); + chrome.test.assertEq(250, window.width); + chrome.test.assertEq(300, window.height); + }); + chrome.windows.create( + { 'url': 'about:blank', + 'type': 'detached_panel', 'top': 42, 'left': 24, + 'width': 250, 'height': 300 }, + chrome.test.callbackPass(createCallback)); + } +]); |