summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/tabs/tabs.cc145
-rw-r--r--chrome/browser/extensions/api/tabs/tabs_constants.cc1
-rw-r--r--chrome/browser/extensions/api/tabs/tabs_constants.h1
-rw-r--r--chrome/browser/extensions/window_open_apitest.cc13
-rw-r--r--chrome/browser/task_manager/task_manager_browsertest.cc3
-rw-r--r--chrome/browser/ui/panels/base_panel_browser_test.cc8
-rw-r--r--chrome/browser/ui/panels/base_panel_browser_test.h3
-rw-r--r--chrome/browser/ui/panels/detached_panel_browsertest.cc8
-rw-r--r--chrome/browser/ui/panels/detached_panel_strip.cc30
-rw-r--r--chrome/browser/ui/panels/detached_panel_strip.h12
-rw-r--r--chrome/browser/ui/panels/panel_cocoa_unittest.mm3
-rw-r--r--chrome/browser/ui/panels/panel_manager.cc48
-rw-r--r--chrome/browser/ui/panels/panel_manager.h19
-rw-r--r--chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm3
-rw-r--r--chrome/browser/ui/panels/panel_view.cc1
-rw-r--r--chrome/common/extensions/api/windows.json4
-rw-r--r--chrome/test/data/extensions/api_test/window_open/panel_detached/manifest.json10
-rw-r--r--chrome/test/data/extensions/api_test/window_open/panel_detached/test.html6
-rw-r--r--chrome/test/data/extensions/api_test/window_open/panel_detached/test.js72
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));
+ }
+]);