summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/app_window.cc3
-rw-r--r--apps/app_window.h3
-rw-r--r--apps/ui/native_app_window.h5
-rw-r--r--apps/ui/views/app_window_frame_view.cc7
-rw-r--r--apps/ui/views/app_window_frame_view.h2
-rw-r--r--chrome/browser/about_flags.cc2
-rw-r--r--chrome/browser/apps/app_window_browsertest.cc12
-rw-r--r--chrome/browser/extensions/api/app_window/app_window_api.cc108
-rw-r--r--chrome/browser/extensions/api/app_window/app_window_api.h18
-rw-r--r--chrome/browser/extensions/api/extension_action/extension_action_api.cc27
-rw-r--r--chrome/browser/extensions/api/extension_action/extension_browser_actions_api_unittest.cc4
-rw-r--r--chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h2
-rw-r--r--chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm10
-rw-r--r--chrome/browser/ui/gtk/apps/native_app_window_gtk.cc8
-rw-r--r--chrome/browser/ui/gtk/apps/native_app_window_gtk.h2
-rw-r--r--chrome/browser/ui/views/apps/native_app_window_views.cc28
-rw-r--r--chrome/browser/ui/views/apps/native_app_window_views.h6
-rw-r--r--chrome/common/extensions/api/app_window.idl14
-rw-r--r--chrome/renderer/resources/extensions/app_window_custom_bindings.js14
-rw-r--r--chrome/test/data/extensions/platform_apps/window_api/test.js112
20 files changed, 334 insertions, 53 deletions
diff --git a/apps/app_window.cc b/apps/app_window.cc
index 99198b0..1f0c945 100644
--- a/apps/app_window.cc
+++ b/apps/app_window.cc
@@ -123,6 +123,7 @@ void AppWindow::SizeConstraints::set_maximum_size(const gfx::Size& max_size) {
AppWindow::CreateParams::CreateParams()
: window_type(AppWindow::WINDOW_TYPE_DEFAULT),
frame(AppWindow::FRAME_CHROME),
+ has_frame_color(false),
transparent_background(false),
bounds(INT_MIN, INT_MIN, 0, 0),
creator_process_id(0),
@@ -610,6 +611,8 @@ void AppWindow::GetSerializedState(base::DictionaryValue* properties) const {
boundsValue->SetInteger("width", bounds.width());
boundsValue->SetInteger("height", bounds.height());
properties->Set("bounds", boundsValue.release());
+ properties->SetBoolean("hasFrameColor", native_app_window_->HasFrameColor());
+ properties->SetInteger("frameColor", native_app_window_->FrameColor());
const SizeConstraints& constraints = size_constraints();
gfx::Size min_size = constraints.GetMinimumSize();
diff --git a/apps/app_window.h b/apps/app_window.h
index 46933c9..9551539 100644
--- a/apps/app_window.h
+++ b/apps/app_window.h
@@ -157,6 +157,9 @@ class AppWindow : public content::NotificationObserver,
WindowType window_type;
Frame frame;
+
+ bool has_frame_color;
+ SkColor frame_color;
bool transparent_background; // Only supported on ash.
// Specify the initial content bounds of the window (excluding any window
diff --git a/apps/ui/native_app_window.h b/apps/ui/native_app_window.h
index 1668916..fe32f53 100644
--- a/apps/ui/native_app_window.h
+++ b/apps/ui/native_app_window.h
@@ -7,6 +7,7 @@
#include "apps/app_window.h"
#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/base_window.h"
#include "ui/gfx/insets.h"
@@ -57,6 +58,10 @@ class NativeAppWindow : public ui::BaseWindow,
// chrome.app.window.create with the option 'frame' set to 'none'.
virtual bool IsFrameless() const = 0;
+ // Returns information about the window's frame.
+ virtual bool HasFrameColor() const = 0;
+ virtual SkColor FrameColor() const = 0;
+
// Returns the difference between the window bounds (including titlebar and
// borders) and the content bounds, if any.
virtual gfx::Insets GetFrameInsets() const = 0;
diff --git a/apps/ui/views/app_window_frame_view.cc b/apps/ui/views/app_window_frame_view.cc
index a8c11c3..d981ee7 100644
--- a/apps/ui/views/app_window_frame_view.cc
+++ b/apps/ui/views/app_window_frame_view.cc
@@ -51,11 +51,13 @@ AppWindowFrameView::AppWindowFrameView(NativeAppWindow* window)
AppWindowFrameView::~AppWindowFrameView() {}
void AppWindowFrameView::Init(views::Widget* frame,
+ const SkColor& frame_color,
int resize_inside_bounds_size,
int resize_outside_bounds_size,
int resize_outside_scale_for_touch,
int resize_area_corner_size) {
frame_ = frame;
+ frame_color_ = frame_color;
resize_inside_bounds_size_ = resize_inside_bounds_size;
resize_outside_bounds_size_ = resize_outside_bounds_size;
resize_area_corner_size_ = resize_area_corner_size;
@@ -156,11 +158,12 @@ int AppWindowFrameView::NonClientHitTest(const gfx::Point& point) {
return HTCLIENT;
gfx::Rect expanded_bounds = bounds();
- if (resize_outside_bounds_size_)
+ if (resize_outside_bounds_size_) {
expanded_bounds.Inset(gfx::Insets(-resize_outside_bounds_size_,
-resize_outside_bounds_size_,
-resize_outside_bounds_size_,
-resize_outside_bounds_size_));
+ }
// Points outside the (possibly expanded) bounds can be discarded.
if (!expanded_bounds.Contains(point))
return HTNOWHERE;
@@ -297,7 +300,7 @@ void AppWindowFrameView::OnPaint(gfx::Canvas* canvas) {
SkPaint paint;
paint.setAntiAlias(false);
paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(SK_ColorWHITE);
+ paint.setColor(frame_color_);
gfx::Path path;
path.moveTo(0, 0);
path.lineTo(width(), 0);
diff --git a/apps/ui/views/app_window_frame_view.h b/apps/ui/views/app_window_frame_view.h
index 77c3859..2be6161 100644
--- a/apps/ui/views/app_window_frame_view.h
+++ b/apps/ui/views/app_window_frame_view.h
@@ -44,6 +44,7 @@ class AppWindowFrameView : public views::NonClientFrameView,
// which a click is interpreted as a resize for the inner and outer border of
// the window and the lower-right corner resize handle.
void Init(views::Widget* frame,
+ const SkColor& frame_color,
int resize_inside_bounds_size,
int resize_outside_bounds_size,
int resize_outside_scale_for_touch,
@@ -75,6 +76,7 @@ class AppWindowFrameView : public views::NonClientFrameView,
NativeAppWindow* window_;
views::Widget* frame_;
+ SkColor frame_color_;
views::ImageButton* close_button_;
views::ImageButton* maximize_button_;
views::ImageButton* restore_button_;
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b76c6d1..cf5fcf4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1533,7 +1533,7 @@ const Experiment kExperiments[] = {
"apps-use-native-frame",
IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_NAME,
IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_DESCRIPTION,
- kOsMac | kOsWin,
+ kOsMac,
SINGLE_VALUE_TYPE(switches::kAppsUseNativeFrame)
},
{
diff --git a/chrome/browser/apps/app_window_browsertest.cc b/chrome/browser/apps/app_window_browsertest.cc
index 234ee3f..468d603 100644
--- a/chrome/browser/apps/app_window_browsertest.cc
+++ b/chrome/browser/apps/app_window_browsertest.cc
@@ -215,3 +215,15 @@ IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestBadging) {
ASSERT_TRUE(
RunAppWindowAPITestAndWaitForRoundTrip("testBadging")) << message_;
}
+
+// TODO(benwells): Implement on Mac.
+#if defined(USE_AURA)
+IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestFrameColors) {
+ ASSERT_TRUE(RunAppWindowAPITest("testFrameColors")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestFrameColorsInStable) {
+ extensions::ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_STABLE);
+ ASSERT_TRUE(RunAppWindowAPITest("testFrameColorsInStable")) << message_;
+}
+#endif
diff --git a/chrome/browser/extensions/api/app_window/app_window_api.cc b/chrome/browser/extensions/api/app_window/app_window_api.cc
index 8015f69..0ff1d3f 100644
--- a/chrome/browser/extensions/api/app_window/app_window_api.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_api.cc
@@ -9,10 +9,12 @@
#include "apps/app_window_registry.h"
#include "apps/ui/native_app_window.h"
#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/apps/chrome_app_window_delegate.h"
@@ -26,6 +28,7 @@
#include "content/public/common/url_constants.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/common/switches.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/rect.h"
#include "url/gurl.h"
@@ -46,9 +49,17 @@ namespace extensions {
namespace app_window_constants {
const char kInvalidWindowId[] =
"The window id can not be more than 256 characters long.";
-}
+const char kInvalidColorSpecification[] =
+ "The color specification could not be parsed.";
+const char kInvalidChannelForFrameOptions[] =
+ "frameOptions is only available in dev channel.";
+const char kFrameOptionsAndFrame[] =
+ "Only one of frame and frameOptions can be supplied.";
+const char kColorWithFrameNone[] = "Windows with no frame cannot have a color.";
+} // namespace app_window_constants
const char kNoneFrameOption[] = "none";
+ // TODO(benwells): Remove HTML titlebar injection.
const char kHtmlFrameOption[] = "experimental-html";
namespace {
@@ -84,6 +95,9 @@ class DevToolsRestorer : public base::RefCounted<DevToolsRestorer> {
} // namespace
+AppWindowCreateFunction::AppWindowCreateFunction()
+ : inject_html_titlebar_(false) {}
+
void AppWindowCreateFunction::SendDelayedResponse() {
SendResponse(true);
}
@@ -105,8 +119,6 @@ bool AppWindowCreateFunction::RunImpl() {
url = absolute;
}
- bool inject_html_titlebar = false;
-
// TODO(jeremya): figure out a way to pass the opening WebContents through to
// AppWindow::Create so we can set the opener at create time rather than
// with a hack in AppWindowCustomBindings::GetView().
@@ -152,6 +164,7 @@ bool AppWindowCreateFunction::RunImpl() {
result->Set("viewId", new base::FundamentalValue(view_id));
window->GetSerializedState(result);
result->SetBoolean("existingWindow", true);
+ // TODO(benwells): Remove HTML titlebar injection.
result->SetBoolean("injectTitlebar", false);
SetResult(result);
SendResponse(true);
@@ -199,19 +212,8 @@ bool AppWindowCreateFunction::RunImpl() {
}
}
- if (options->frame.get()) {
- if (*options->frame == kHtmlFrameOption &&
- (GetExtension()->HasAPIPermission(APIPermission::kExperimental) ||
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableExperimentalExtensionApis))) {
- create_params.frame = AppWindow::FRAME_NONE;
- inject_html_titlebar = true;
- } else if (*options->frame == kNoneFrameOption) {
- create_params.frame = AppWindow::FRAME_NONE;
- } else {
- create_params.frame = AppWindow::FRAME_CHROME;
- }
- }
+ if (!GetFrameOptions(*options, &create_params))
+ return false;
if (options->transparent_background.get() &&
(GetExtension()->HasAPIPermission(APIPermission::kExperimental) ||
@@ -262,6 +264,8 @@ bool AppWindowCreateFunction::RunImpl() {
}
}
+ UpdateFrameOptionsForChannel(&create_params);
+
create_params.creator_process_id =
render_view_host_->GetProcess()->GetID();
@@ -282,7 +286,7 @@ bool AppWindowCreateFunction::RunImpl() {
base::DictionaryValue* result = new base::DictionaryValue;
result->Set("viewId", new base::FundamentalValue(view_id));
result->Set("injectTitlebar",
- new base::FundamentalValue(inject_html_titlebar));
+ new base::FundamentalValue(inject_html_titlebar_));
result->Set("id", new base::StringValue(app_window->window_key()));
app_window->GetSerializedState(result);
SetResult(result);
@@ -297,4 +301,74 @@ bool AppWindowCreateFunction::RunImpl() {
return true;
}
+AppWindow::Frame AppWindowCreateFunction::GetFrameFromString(
+ const std::string& frame_string) {
+ if (frame_string == kHtmlFrameOption &&
+ (GetExtension()->HasAPIPermission(APIPermission::kExperimental) ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalExtensionApis))) {
+ inject_html_titlebar_ = true;
+ return AppWindow::FRAME_NONE;
+ }
+
+ if (frame_string == kNoneFrameOption)
+ return AppWindow::FRAME_NONE;
+
+ return AppWindow::FRAME_CHROME;
+}
+
+bool AppWindowCreateFunction::GetFrameOptions(
+ const app_window::CreateWindowOptions& options,
+ AppWindow::CreateParams* create_params) {
+ if (options.frame.get() && options.frame_options.get()) {
+ error_ = app_window_constants::kFrameOptionsAndFrame;
+ return false;
+ }
+
+ if (options.frame.get())
+ create_params->frame = GetFrameFromString(*options.frame);
+
+ if (options.frame_options.get()) {
+ if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV) {
+ app_window::FrameOptions* frame_options = options.frame_options.get();
+
+ if (frame_options->type.get())
+ create_params->frame = GetFrameFromString(*frame_options->type);
+
+ if (frame_options->color.get()) {
+ if (create_params->frame != AppWindow::FRAME_CHROME) {
+ error_ = app_window_constants::kColorWithFrameNone;
+ return false;
+ }
+
+ if (ExtensionActionFunction::ParseCSSColorString(
+ *frame_options->color,
+ &create_params->frame_color)) {
+ create_params->has_frame_color = true;
+ } else {
+ error_ = app_window_constants::kInvalidColorSpecification;
+ return false;
+ }
+ }
+ } else {
+ error_ = app_window_constants::kInvalidChannelForFrameOptions;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void AppWindowCreateFunction::UpdateFrameOptionsForChannel(
+ apps::AppWindow::CreateParams* create_params) {
+ if (create_params->frame == AppWindow::FRAME_CHROME &&
+ GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV) {
+ // If not on trunk or dev channel, always use the standard white frame.
+ // TODO(benwells): Remove this code once we get agreement to use the new
+ // native style frame.
+ create_params->has_frame_color = true;
+ create_params->frame_color = SK_ColorWHITE;
+ }
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/api/app_window/app_window_api.h b/chrome/browser/extensions/api/app_window/app_window_api.h
index 8aaac544..28c3585 100644
--- a/chrome/browser/extensions/api/app_window/app_window_api.h
+++ b/chrome/browser/extensions/api/app_window/app_window_api.h
@@ -5,12 +5,20 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_APP_WINDOW_APP_WINDOW_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_APP_WINDOW_APP_WINDOW_API_H_
+#include "apps/app_window.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
namespace extensions {
+namespace api {
+namespace app_window {
+struct CreateWindowOptions;
+}
+}
+
class AppWindowCreateFunction : public ChromeAsyncExtensionFunction {
public:
+ AppWindowCreateFunction();
DECLARE_EXTENSION_FUNCTION("app.window.create", APP_WINDOW_CREATE)
void SendDelayedResponse();
@@ -18,6 +26,16 @@ class AppWindowCreateFunction : public ChromeAsyncExtensionFunction {
protected:
virtual ~AppWindowCreateFunction() {}
virtual bool RunImpl() OVERRIDE;
+
+ private:
+ bool inject_html_titlebar_;
+
+ apps::AppWindow::Frame GetFrameFromString(const std::string& frame_string);
+ bool GetFrameOptions(
+ const extensions::api::app_window::CreateWindowOptions& options,
+ apps::AppWindow::CreateParams* create_params);
+ void UpdateFrameOptionsForChannel(
+ apps::AppWindow::CreateParams* create_params);
};
} // namespace extensions
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 1446db7..a34dc7e 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -638,36 +638,31 @@ void ExtensionActionFunction::NotifySystemIndicatorChange() {
bool ExtensionActionFunction::ParseCSSColorString(
const std::string& color_string,
SkColor* result) {
- std::string formatted_color = "#";
+ std::string formatted_color;
// Check the string for incorrect formatting.
- if (color_string[0] != '#')
+ if (color_string.empty() || color_string[0] != '#')
return false;
// Convert the string from #FFF format to #FFFFFF format.
if (color_string.length() == 4) {
- for (size_t i = 1; i < color_string.length(); i++) {
+ for (size_t i = 1; i < 4; ++i) {
formatted_color += color_string[i];
formatted_color += color_string[i];
}
+ } else if (color_string.length() == 7) {
+ formatted_color = color_string.substr(1, 6);
} else {
- formatted_color = color_string;
- }
-
- if (formatted_color.length() != 7)
return false;
+ }
// Convert the string to an integer and make sure it is in the correct value
// range.
- int color_ints[3] = {0};
- for (int i = 0; i < 3; i++) {
- if (!base::HexStringToInt(formatted_color.substr(1 + (2 * i), 2),
- color_ints + i))
- return false;
- if (color_ints[i] > 255 || color_ints[i] < 0)
- return false;
- }
+ std::vector<uint8> color_bytes;
+ if (!base::HexStringToBytes(formatted_color, &color_bytes))
+ return false;
- *result = SkColorSetARGB(255, color_ints[0], color_ints[1], color_ints[2]);
+ DCHECK_EQ(3u, color_bytes.size());
+ *result = SkColorSetARGB(255, color_bytes[0], color_bytes[1], color_bytes[2]);
return true;
}
diff --git a/chrome/browser/extensions/api/extension_action/extension_browser_actions_api_unittest.cc b/chrome/browser/extensions/api/extension_action/extension_browser_actions_api_unittest.cc
index 79e99ad..e2d615d 100644
--- a/chrome/browser/extensions/api/extension_action/extension_browser_actions_api_unittest.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_browser_actions_api_unittest.cc
@@ -49,4 +49,8 @@ TEST(ExtensionBrowserActionsApiTest, ChangeBadgeBackgroundCSSInvalid) {
RunFailTest("#-22128");
}
+TEST(ExtensionBrowserActionsApiTest, ChangeBadgeBackgroundCSSInvalidWithPlus) {
+ RunFailTest("#+22128");
+}
+
} // namespace extensions
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
index 9f05cc0..ed77dad 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
@@ -125,6 +125,8 @@ class NativeAppWindowCocoa : public apps::NativeAppWindow,
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
virtual bool IsFrameless() const OVERRIDE;
+ virtual bool HasFrameColor() const OVERRIDE;
+ virtual SkColor FrameColor() const OVERRIDE;
virtual gfx::Insets GetFrameInsets() const OVERRIDE;
// These are used to simulate Mac-style hide/show. Since windows can be hidden
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
index a6a01ad..1fcd0a5 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
@@ -835,6 +835,16 @@ bool NativeAppWindowCocoa::IsFrameless() const {
return !has_frame_;
}
+bool NativeAppWindowCocoa::HasFrameColor() const {
+ // TODO(benwells): Implement this.
+ return false;
+}
+
+SkColor NativeAppWindowCocoa::FrameColor() const {
+ // TODO(benwells): Implement this.
+ return SkColor();
+}
+
gfx::Insets NativeAppWindowCocoa::GetFrameInsets() const {
if (!has_frame_)
return gfx::Insets();
diff --git a/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc b/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
index 888f106..f8f52bf 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
@@ -668,6 +668,14 @@ bool NativeAppWindowGtk::IsFrameless() const {
return frameless_;
}
+bool NativeAppWindowGtk::HasFrameColor() const {
+ return false;
+}
+
+SkColor NativeAppWindowGtk::FrameColor() const {
+ return SkColor();
+}
+
gfx::Insets NativeAppWindowGtk::GetFrameInsets() const {
if (frameless_)
return gfx::Insets();
diff --git a/chrome/browser/ui/gtk/apps/native_app_window_gtk.h b/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
index 6b4cc65..c324ed8 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
@@ -79,6 +79,8 @@ class NativeAppWindowGtk : public apps::NativeAppWindow,
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
virtual bool IsFrameless() const OVERRIDE;
+ virtual bool HasFrameColor() const OVERRIDE;
+ virtual SkColor FrameColor() const OVERRIDE;
virtual gfx::Insets GetFrameInsets() const OVERRIDE;
virtual void HideWithApp() OVERRIDE;
virtual void ShowWithApp() OVERRIDE;
diff --git a/chrome/browser/ui/views/apps/native_app_window_views.cc b/chrome/browser/ui/views/apps/native_app_window_views.cc
index e465d1f..eb886b4 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/native_app_window_views.cc
@@ -211,6 +211,8 @@ void NativeAppWindowViews::Init(apps::AppWindow* app_window,
const AppWindow::CreateParams& create_params) {
app_window_ = app_window;
frameless_ = create_params.frame == AppWindow::FRAME_NONE;
+ has_frame_color_ = create_params.has_frame_color;
+ frame_color_ = create_params.frame_color;
transparent_background_ = create_params.transparent_background;
resizable_ = create_params.resizable;
Observe(web_contents());
@@ -232,7 +234,7 @@ void NativeAppWindowViews::Init(apps::AppWindow* app_window,
window_->AddObserver(this);
#if defined(OS_WIN)
- if (ShouldUseChromeStyleFrame() &&
+ if (ShouldUseNativeFrame() &&
chrome::GetHostDesktopTypeForNativeWindow(window_->GetNativeWindow()) !=
chrome::HOST_DESKTOP_TYPE_ASH) {
InstallEasyResizeTargeterOnContainer();
@@ -255,7 +257,7 @@ void NativeAppWindowViews::InitializeDefaultWindow(
views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW);
init_params.delegate = this;
- init_params.remove_standard_frame = ShouldUseChromeStyleFrame();
+ init_params.remove_standard_frame = !ShouldUseNativeFrame();
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// On Linux, remove the standard frame. Instead, we will use CustomFrameView
// to draw a native-like frame.
@@ -376,17 +378,8 @@ void NativeAppWindowViews::InitializePanelWindow(
#endif
}
-bool NativeAppWindowViews::ShouldUseChromeStyleFrame() const {
- if (frameless_)
- return true;
-
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- // Linux always uses native style frames.
- return false;
-#endif
-
- return !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAppsUseNativeFrame);
+bool NativeAppWindowViews::ShouldUseNativeFrame() const {
+ return !frameless_ & !has_frame_color_;
}
void NativeAppWindowViews::InstallEasyResizeTargeterOnContainer() const {
@@ -415,6 +408,7 @@ apps::AppWindowFrameView* NativeAppWindowViews::CreateAppWindowFrameView() {
#endif
apps::AppWindowFrameView* frame_view = new apps::AppWindowFrameView(this);
frame_view->Init(window_,
+ frame_color_,
resize_inside_bounds_size,
resize_outside_bounds_size,
resize_outside_scale_for_touch,
@@ -638,7 +632,7 @@ bool NativeAppWindowViews::CanMaximize() const {
}
base::string16 NativeAppWindowViews::GetWindowTitle() const {
- return app_window_->GetTitle();
+ return base::string16();
}
bool NativeAppWindowViews::ShouldShowWindowTitle() const {
@@ -730,7 +724,7 @@ views::NonClientFrameView* NativeAppWindowViews::CreateNonClientFrameView(
}
}
#endif
- if (ShouldUseChromeStyleFrame())
+ if (!ShouldUseNativeFrame())
return CreateAppWindowFrameView();
return views::WidgetDelegateView::CreateNonClientFrameView(widget);
}
@@ -972,6 +966,10 @@ bool NativeAppWindowViews::IsFrameless() const {
return frameless_;
}
+bool NativeAppWindowViews::HasFrameColor() const { return has_frame_color_; }
+
+SkColor NativeAppWindowViews::FrameColor() const { return frame_color_; }
+
gfx::Insets NativeAppWindowViews::GetFrameInsets() const {
if (frameless_)
return gfx::Insets();
diff --git a/chrome/browser/ui/views/apps/native_app_window_views.h b/chrome/browser/ui/views/apps/native_app_window_views.h
index 3146b6e..f056649 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.h
+++ b/chrome/browser/ui/views/apps/native_app_window_views.h
@@ -91,7 +91,7 @@ class NativeAppWindowViews : public apps::NativeAppWindow,
void OnViewWasResized();
- bool ShouldUseChromeStyleFrame() const;
+ bool ShouldUseNativeFrame() const;
// Installs an EasyResizeWindowTargeter on the containing window, which
// allows the window to be resized from within |kResizeInsideBoundsSize|
@@ -188,6 +188,8 @@ class NativeAppWindowViews : public apps::NativeAppWindow,
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
virtual bool IsFrameless() const OVERRIDE;
+ virtual bool HasFrameColor() const OVERRIDE;
+ virtual SkColor FrameColor() const OVERRIDE;
virtual gfx::Insets GetFrameInsets() const OVERRIDE;
virtual void HideWithApp() OVERRIDE;
virtual void ShowWithApp() OVERRIDE;
@@ -216,6 +218,8 @@ class NativeAppWindowViews : public apps::NativeAppWindow,
scoped_ptr<SkRegion> draggable_region_;
bool frameless_;
+ bool has_frame_color_;
+ SkColor frame_color_;
bool transparent_background_;
gfx::Size preferred_size_;
bool resizable_;
diff --git a/chrome/common/extensions/api/app_window.idl b/chrome/common/extensions/api/app_window.idl
index fb13c13..73fec64 100644
--- a/chrome/common/extensions/api/app_window.idl
+++ b/chrome/common/extensions/api/app_window.idl
@@ -13,6 +13,12 @@ namespace app.window {
long? height;
};
+ // TODO(benwells): document this once we are happy with it.
+ [nodoc] dictionary FrameOptions {
+ DOMString? type;
+ DOMString? color;
+ };
+
// State of a window: normal, fullscreen, maximized, minimized.
enum State { normal, fullscreen, maximized, minimized };
@@ -76,6 +82,10 @@ namespace app.window {
// to disable this style on nested elements.
DOMString? frame;
+ // TODO(benwells): Fix the IDL parsing so this can be:
+ // (DOMString or FrameOptions)? frame.
+ [nodoc] FrameOptions? frameOptions;
+
// Size and position of the content in the window (excluding the titlebar).
// If an id is also specified and a window with a matching id has been shown
// before, the remembered bounds of the window will be used instead.
@@ -232,6 +242,10 @@ namespace app.window {
// Is the window always on top?
static boolean isAlwaysOnTop();
+ // Accessors for testing.
+ [nodoc] boolean hasFrameColor;
+ [nodoc] long frameColor;
+
// Set whether the window should stay above most other windows. Requires the
// <code>"alwaysOnTopWindows"</code> permission.
static void setAlwaysOnTop(boolean alwaysOnTop);
diff --git a/chrome/renderer/resources/extensions/app_window_custom_bindings.js b/chrome/renderer/resources/extensions/app_window_custom_bindings.js
index dd9d8e3..22eb37b 100644
--- a/chrome/renderer/resources/extensions/app_window_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/app_window_custom_bindings.js
@@ -146,6 +146,16 @@ appWindow.registerCustomHook(function(bindingsAPI) {
return appWindowData.id;
}});
+ // These properties are for testing.
+ Object.defineProperty(
+ AppWindow.prototype, 'hasFrameColor', {get: function() {
+ return appWindowData.hasFrameColor;
+ }});
+
+ Object.defineProperty(AppWindow.prototype, 'frameColor', {get: function() {
+ return appWindowData.frameColor;
+ }});
+
appWindowData = {
id: params.id || '',
bounds: { left: params.bounds.left, top: params.bounds.top,
@@ -157,7 +167,9 @@ appWindow.registerCustomHook(function(bindingsAPI) {
fullscreen: params.fullscreen,
minimized: params.minimized,
maximized: params.maximized,
- alwaysOnTop: params.alwaysOnTop
+ alwaysOnTop: params.alwaysOnTop,
+ hasFrameColor: params.hasFrameColor,
+ frameColor: params.frameColor
};
currentAppWindow = new AppWindow;
});
diff --git a/chrome/test/data/extensions/platform_apps/window_api/test.js b/chrome/test/data/extensions/platform_apps/window_api/test.js
index 42f8a40..eb2e86b 100644
--- a/chrome/test/data/extensions/platform_apps/window_api/test.js
+++ b/chrome/test/data/extensions/platform_apps/window_api/test.js
@@ -3,6 +3,7 @@
// found in the LICENSE file.
var callbackPass = chrome.test.callbackPass;
+var callbackFail = chrome.test.callbackFail;
var defaultFuzzFactor = 1;
function assertFuzzyEq(expected, actual, fuzzFactor, message) {
@@ -559,6 +560,117 @@ function testBadging() {
]);
}
+function testFrameColors() {
+ chrome.test.runTests([
+ function testWithNoColor() {
+ chrome.app.window.create('test.html', callbackPass(function(win) {
+ chrome.test.assertEq(false, win.hasFrameColor);
+ win.close();
+ }));
+ },
+
+ function testWithFrameNone() {
+ chrome.app.window.create('test.html', {
+ frame: 'none'
+ },
+ callbackPass(function(win) {
+ chrome.test.assertEq(false, win.hasFrameColor);
+ win.close();
+ }));
+ },
+
+ function testWithBlack() {
+ chrome.app.window.create('test.html', {
+ frameOptions: {
+ type: 'chrome',
+ color: '#000000'
+ }
+ },
+ callbackPass(function(win) {
+ chrome.test.assertEq(true, win.hasFrameColor);
+ chrome.test.assertEq(-16777216, win.frameColor);
+ win.close();
+ }));
+ },
+
+ function testWithWhite() {
+ chrome.app.window.create('test.html', {
+ frameOptions: {
+ color: '#FFFFFF'
+ }
+ },
+ callbackPass(function(win) {
+ chrome.test.assertEq(true, win.hasFrameColor);
+ chrome.test.assertEq(-1, win.frameColor);
+ win.close();
+ }));
+ },
+
+ function testWithWhiteShorthand() {
+ chrome.app.window.create('test.html', {
+ frameOptions: {
+ color: '#FFF'
+ }
+ },
+ callbackPass(function(win) {
+ chrome.test.assertEq(true, win.hasFrameColor);
+ chrome.test.assertEq(-1, win.frameColor);
+ win.close();
+ }));
+ },
+
+ function testWithFrameAndFrameOptions() {
+ chrome.app.window.create('test.html', {
+ frame: 'chrome',
+ frameOptions: {
+ color: '#FFF'
+ }
+ },
+ callbackFail('Only one of frame and frameOptions can be supplied.'));
+ },
+
+ function testWithFrameNoneAndColor() {
+ chrome.app.window.create('test.html', {
+ frameOptions: {
+ type: 'none',
+ color: '#FFF'
+ }
+ },
+ callbackFail('Windows with no frame cannot have a color.'));
+ },
+
+ function testWithInvalidColor() {
+ chrome.app.window.create('test.html', {
+ frameOptions: {
+ color: 'DontWorryBeHappy'
+ }
+ },
+ callbackFail('The color specification could not be parsed.'));
+ }
+ ]);
+}
+
+function testFrameColorsInStable() {
+ chrome.test.runTests([
+ function testWithNoColor() {
+ chrome.app.window.create('test.html', callbackPass(function(win) {
+ chrome.test.assertEq(true, win.hasFrameColor);
+ chrome.test.assertEq(-1, win.frameColor);
+ win.close();
+ }));
+ },
+
+ function testWithOptionsGivesError() {
+ chrome.app.window.create('test.html', {
+ frameOptions: {
+ color: '#FFF'
+ }
+ },
+ callbackFail('frameOptions is only available in dev channel.'));
+ }
+ ]);
+}
+
chrome.app.runtime.onLaunched.addListener(function() {
chrome.test.sendMessage('Launched', function(reply) {
window[reply]();