diff options
author | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-28 04:42:43 +0000 |
---|---|---|
committer | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-28 04:42:43 +0000 |
commit | 99d8f096aa417b8b94f0d0dafb4350bd19607758 (patch) | |
tree | b54cc08ca43f0776dbe497d8c9caa72e414c4b0c | |
parent | 7240505e7e7c1aa3e866c13ef614bf1409c17eeb (diff) | |
download | chromium_src-99d8f096aa417b8b94f0d0dafb4350bd19607758.zip chromium_src-99d8f096aa417b8b94f0d0dafb4350bd19607758.tar.gz chromium_src-99d8f096aa417b8b94f0d0dafb4350bd19607758.tar.bz2 |
Add app window property change events
This adds onBoundsChanged, onMinimized, onMaximized, and onRestored events.
BUG=134070
Review URL: https://codereview.chromium.org/11364230
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169848 0039d316-1c4b-4281-b951-d872f2087c98
15 files changed, 236 insertions, 44 deletions
diff --git a/chrome/browser/extensions/api/app_window/app_window_apitest.cc b/chrome/browser/extensions/api/app_window/app_window_apitest.cc index 09d42b4..5307888 100644 --- a/chrome/browser/extensions/api/app_window/app_window_apitest.cc +++ b/chrome/browser/extensions/api/app_window/app_window_apitest.cc @@ -37,4 +37,16 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, WindowsApiBounds) { ASSERT_TRUE(success_listener.WaitUntilSatisfied()); } +// TODO(asargent) - Fix onMinimzed event on OSX (crbug.com/162793) and figure +// out what to do about the fact that minimize events don't work under ubuntu +// unity (crbug.com/162794 and https://bugs.launchpad.net/unity/+bug/998073). +#if defined(TOOLKIT_VIEWS) + +IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, WindowsApiProperties) { + EXPECT_TRUE( + RunExtensionTest("platform_apps/windows_api_properties")) << message_; +} + +#endif // defined(TOOLKIT_VIEWS) + } // namespace extensions diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc index 46b176f..3736e0a 100644 --- a/chrome/browser/extensions/platform_app_browsertest.cc +++ b/chrome/browser/extensions/platform_app_browsertest.cc @@ -655,9 +655,9 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, } // In the GTK ShellWindow implementation there also is a delay between - // getting the correct bounds and it calling SaveWindowPosition, so call that + // getting the correct bounds and it calling SaveWindowPosition, so call a // method explicitly to make sure the value was stored. - window->SaveWindowPosition(); + window->OnNativeWindowChanged(); #endif // defined(TOOLKIT_GTK) // Make sure the window was properly moved&resized. diff --git a/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm b/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm index 779564f..34143a2 100644 --- a/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm @@ -656,7 +656,7 @@ bool ShellWindowCocoa::IsAlwaysOnTop() const { void ShellWindowCocoa::WindowWillClose() { [window_controller_ setShellWindow:NULL]; - shell_window_->SaveWindowPosition(); + shell_window_->OnNativeWindowChanged(); shell_window_->OnNativeClose(); } @@ -682,11 +682,11 @@ void ShellWindowCocoa::WindowDidResignKey() { } void ShellWindowCocoa::WindowDidResize() { - shell_window_->SaveWindowPosition(); + shell_window_->OnNativeWindowChanged(); } void ShellWindowCocoa::WindowDidMove() { - shell_window_->SaveWindowPosition(); + shell_window_->OnNativeWindowChanged(); } bool ShellWindowCocoa::HandledByExtensionCommand(NSEvent* event) { diff --git a/chrome/browser/ui/extensions/shell_window.cc b/chrome/browser/ui/extensions/shell_window.cc index 7406536..71e9459 100644 --- a/chrome/browser/ui/extensions/shell_window.cc +++ b/chrome/browser/ui/extensions/shell_window.cc @@ -5,6 +5,7 @@ #include "chrome/browser/ui/extensions/shell_window.h" #include "base/utf_string_conversions.h" +#include "base/values.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/shell_window_geometry_cache.h" @@ -143,7 +144,7 @@ void ShellWindow::Init(const GURL& url, new_params.bounds = bounds; native_window_.reset(NativeShellWindow::Create(this, new_params)); - SaveWindowPosition(); + OnNativeWindowChanged(); if (!params.hidden) GetBaseWindow()->Show(); @@ -287,6 +288,34 @@ void ShellWindow::OnNativeClose() { delete this; } +void ShellWindow::OnNativeWindowChanged() { + SaveWindowPosition(); + if (!native_window_ || !web_contents_) + return; + ListValue args; + DictionaryValue* dictionary = new DictionaryValue(); + args.Append(dictionary); + + gfx::Rect bounds = native_window_->GetBounds(); + app_window::Bounds update; + update.left.reset(new int(bounds.x())); + update.top.reset(new int(bounds.y())); + update.width.reset(new int(bounds.width())); + update.height.reset(new int(bounds.height())); + dictionary->Set("bounds", update.ToValue().release()); + dictionary->SetBoolean("minimized", native_window_->IsMinimized()); + dictionary->SetBoolean("maximized", native_window_->IsMaximized()); + + content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); + rvh->Send(new ExtensionMsg_MessageInvoke(rvh->GetRoutingID(), + extension_->id(), + "updateAppWindowProperties", + args, + GURL(), + false)); +} + + BaseWindow* ShellWindow::GetBaseWindow() { return native_window_.get(); } @@ -460,28 +489,8 @@ void ShellWindow::AddMessageToDevToolsConsole(ConsoleMessageLevel level, rvh->GetRoutingID(), level, message)); } -void ShellWindow::SendBoundsUpdate() { - if (!native_window_ || !web_contents_) - return; - gfx::Rect bounds = native_window_->GetBounds(); - content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); - ListValue args; - app_window::Bounds update; - update.left.reset(new int(bounds.x())); - update.top.reset(new int(bounds.y())); - update.width.reset(new int(bounds.width())); - update.height.reset(new int(bounds.height())); - args.Append(update.ToValue().release()); - rvh->Send(new ExtensionMsg_MessageInvoke(rvh->GetRoutingID(), - extension_->id(), - "updateAppWindowBounds", - args, - GURL(), - false)); -} void ShellWindow::SaveWindowPosition() { - SendBoundsUpdate(); if (window_key_.empty()) return; if (!native_window_) diff --git a/chrome/browser/ui/extensions/shell_window.h b/chrome/browser/ui/extensions/shell_window.h index 2f8b89c..a367e56 100644 --- a/chrome/browser/ui/extensions/shell_window.h +++ b/chrome/browser/ui/extensions/shell_window.h @@ -101,9 +101,9 @@ class ShellWindow : public content::NotificationObserver, // invoke this method instead of using "delete this". void OnNativeClose(); - // Should be called by native implementations when the window size/position - // has changed. - void SaveWindowPosition(); + // Should be called by native implementations when the window size, position, + // or minimized/maximized state has changed. + void OnNativeWindowChanged(); protected: ShellWindow(Profile* profile, @@ -174,8 +174,8 @@ class ShellWindow : public content::NotificationObserver, void AddMessageToDevToolsConsole(content::ConsoleMessageLevel level, const std::string& message); - // Sends an update message with the current bounds to the renderer. - void SendBoundsUpdate(); + // Saves the window geometry/position. + void SaveWindowPosition(); virtual void UpdateDraggableRegions( const std::vector<extensions::DraggableRegion>& regions); diff --git a/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc b/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc index 32e7c73..f636c15 100644 --- a/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc @@ -173,7 +173,7 @@ void ShellWindowGtk::Hide() { } void ShellWindowGtk::Close() { - shell_window_->SaveWindowPosition(); + shell_window_->OnNativeWindowChanged(); // Cancel any pending callback from the window configure debounce timer. window_configure_debounce_timer_.Stop(); @@ -204,6 +204,7 @@ void ShellWindowGtk::Maximize() { void ShellWindowGtk::Minimize() { gtk_window_iconify(window_); + shell_window_->OnNativeWindowChanged(); } void ShellWindowGtk::Restore() { @@ -211,6 +212,7 @@ void ShellWindowGtk::Restore() { gtk_window_unmaximize(window_); else if (IsMinimized()) gtk_window_deiconify(window_); + shell_window_->OnNativeWindowChanged(); } void ShellWindowGtk::SetBounds(const gfx::Rect& bounds) { @@ -275,7 +277,7 @@ gboolean ShellWindowGtk::OnConfigure(GtkWidget* widget, void ShellWindowGtk::OnDebouncedBoundsChanged() { gtk_window_util::UpdateWindowPosition(this, &bounds_, &restored_bounds_); - shell_window_->SaveWindowPosition(); + shell_window_->OnNativeWindowChanged(); } gboolean ShellWindowGtk::OnWindowState(GtkWidget* sender, @@ -290,6 +292,7 @@ gboolean ShellWindowGtk::OnWindowState(GtkWidget* sender, rvh->ExitFullscreen(); } + shell_window_->OnNativeWindowChanged(); return FALSE; } diff --git a/chrome/browser/ui/views/extensions/shell_window_views.cc b/chrome/browser/ui/views/extensions/shell_window_views.cc index c8e0ec9..dcebae2 100644 --- a/chrome/browser/ui/views/extensions/shell_window_views.cc +++ b/chrome/browser/ui/views/extensions/shell_window_views.cc @@ -434,6 +434,7 @@ ShellWindowViews::ShellWindowViews(ShellWindow* shell_window, shell_window_)); OnViewWasResized(); + window_->AddObserver(this); } views::View* ShellWindowViews::GetInitiallyFocusedView() { @@ -575,6 +576,7 @@ bool ShellWindowViews::IsAlwaysOnTop() const { } void ShellWindowViews::DeleteDelegate() { + window_->RemoveObserver(this); shell_window_->OnNativeClose(); } @@ -693,7 +695,17 @@ bool ShellWindowViews::ShouldShowWindowTitle() const { } void ShellWindowViews::OnWidgetMove() { - shell_window_->SaveWindowPosition(); + shell_window_->OnNativeWindowChanged(); +} + +void ShellWindowViews::OnWidgetVisibilityChanged(views::Widget* widget, + bool visible) { + shell_window_->OnNativeWindowChanged(); +} + +void ShellWindowViews::OnWidgetActivationChanged(views::Widget* widget, + bool active) { + shell_window_->OnNativeWindowChanged(); } void ShellWindowViews::Layout() { @@ -733,7 +745,7 @@ void ShellWindowViews::RenderViewHostChanged() { void ShellWindowViews::SaveWindowPlacement(const gfx::Rect& bounds, ui::WindowShowState show_state) { views::WidgetDelegate::SaveWindowPlacement(bounds, show_state); - shell_window_->SaveWindowPosition(); + shell_window_->OnNativeWindowChanged(); } // static diff --git a/chrome/browser/ui/views/extensions/shell_window_views.h b/chrome/browser/ui/views/extensions/shell_window_views.h index 18beabf..d58422b 100644 --- a/chrome/browser/ui/views/extensions/shell_window_views.h +++ b/chrome/browser/ui/views/extensions/shell_window_views.h @@ -13,6 +13,7 @@ #include "ui/gfx/image/image_skia.h" #include "ui/gfx/rect.h" #include "ui/views/widget/widget_delegate.h" +#include "ui/views/widget/widget_observer.h" class ExtensionKeybindingRegistryViews; class Profile; @@ -30,7 +31,8 @@ class WebView; } class ShellWindowViews : public NativeShellWindow, - public views::WidgetDelegateView { + public views::WidgetDelegateView, + public views::WidgetObserver { public: ShellWindowViews(ShellWindow* shell_window, const ShellWindow::CreateParams& params); @@ -78,6 +80,12 @@ class ShellWindowViews : public NativeShellWindow, virtual bool ShouldShowWindowTitle() const OVERRIDE; virtual void OnWidgetMove() OVERRIDE; + // WidgetObserver implementation. + virtual void OnWidgetVisibilityChanged(views::Widget* widget, + bool visible) OVERRIDE; + virtual void OnWidgetActivationChanged(views::Widget* widget, + bool active) OVERRIDE; + protected: // views::View implementation. virtual void Layout() OVERRIDE; diff --git a/chrome/common/extensions/api/app_current_window_internal.idl b/chrome/common/extensions/api/app_current_window_internal.idl index e1a4b3d..782b882 100644 --- a/chrome/common/extensions/api/app_current_window_internal.idl +++ b/chrome/common/extensions/api/app_current_window_internal.idl @@ -28,4 +28,12 @@ static void hide(); static void setBounds(Bounds bounds); }; + + interface Events { + static void onClosed(); + static void onBoundsChanged(); + static void onMinimized(); + static void onMaximized(); + static void onRestored(); + }; }; diff --git a/chrome/common/extensions/api/app_window.idl b/chrome/common/extensions/api/app_window.idl index e2d04ab..3ca6fb9 100644 --- a/chrome/common/extensions/api/app_window.idl +++ b/chrome/common/extensions/api/app_window.idl @@ -83,9 +83,15 @@ namespace app.window { // Minimize the window. static void minimize(); + // Is the window minimized? + static boolean isMinimized(); + // Maximize the window. static void maximize(); + // Is the window maximized? + static bool isMaximized(); + // Restore the window. static void restore(); diff --git a/chrome/renderer/resources/extensions/app_window_custom_bindings.js b/chrome/renderer/resources/extensions/app_window_custom_bindings.js index 9d38b6d..4d454f0 100644 --- a/chrome/renderer/resources/extensions/app_window_custom_bindings.js +++ b/chrome/renderer/resources/extensions/app_window_custom_bindings.js @@ -88,6 +88,12 @@ chromeHidden.registerCustomHook('app.window', function(bindingsAPI) { return { left: bounds.left, top: bounds.top, width: bounds.width, height: bounds.height }; }; + AppWindow.prototype.isMinimized = function() { + return chromeHidden.appWindowData.minimized; + }; + AppWindow.prototype.isMaximized = function() { + return chromeHidden.appWindowData.maximized; + }; Object.defineProperty(AppWindow.prototype, 'id', {get: function() { return chromeHidden.appWindowData.id; @@ -96,18 +102,39 @@ chromeHidden.registerCustomHook('app.window', function(bindingsAPI) { chromeHidden.appWindowData = { id: params.id || '', bounds: { left: params.bounds.left, top: params.bounds.top, - width: params.bounds.width, height: params.bounds.height } + width: params.bounds.width, height: params.bounds.height }, + minimized: false, + maximized: false }; chromeHidden.currentAppWindow = new AppWindow; }); }); -chromeHidden.updateAppWindowBounds = function(info) { - var data = chromeHidden.appWindowData; - if (!data) +function boundsEqual(bounds1, bounds2) { + if (!bounds1 || !bounds2) + return false; + return (bounds1.left == bounds2.left && bounds1.top == bounds2.top && + bounds1.width == bounds2.width && bounds1.height == bounds2.height); +} + +chromeHidden.updateAppWindowProperties = function(update) { + if (!chromeHidden.appWindowData) return; - data.bounds.left = info.left; - data.bounds.top = info.top; - data.bounds.width = info.width; - data.bounds.height = info.height; + var oldData = chromeHidden.appWindowData; + update.id = oldData.id; + chromeHidden.appWindowData = update; + + var currentWindow = chromeHidden.currentAppWindow; + + if (!boundsEqual(oldData.bounds, update.bounds)) + currentWindow["onBoundsChanged"].dispatch(); + + if (!oldData.minimized && update.minimized) + currentWindow["onMinimized"].dispatch(); + if (!oldData.maximized && update.maximized) + currentWindow["onMaximized"].dispatch(); + + if ((oldData.minimized && !update.minimized) || + (oldData.maximized && !update.maximized)) + currentWindow["onRestored"].dispatch(); }; diff --git a/chrome/test/data/extensions/platform_apps/windows_api_properties/background.js b/chrome/test/data/extensions/platform_apps/windows_api_properties/background.js new file mode 100644 index 0000000..e59a6c0 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/windows_api_properties/background.js @@ -0,0 +1,40 @@ +// 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. + +var eventCounts = {}; +var eventCallback = null; + +function clearEventCounts() { + eventCallback = null; + eventCounts['onBoundsChanged'] = 0; + eventCounts['onMinimized'] = 0; + eventCounts['onMaximized'] = 0; + eventCounts['onRestored'] = 0; +} + +clearEventCounts(); + +chrome.app.window.create('main.html', function(win) { + win.onBoundsChanged.addListener(function() { + eventCounts['onBoundsChanged']++; + if (eventCallback) + eventCallback(); + }); + win.onMinimized.addListener(function() { + eventCounts['onMinimized']++; + if (eventCallback) + eventCallback(); + }); + win.onMaximized.addListener(function() { + eventCounts['onMaximized']++; + if (eventCallback) + eventCallback(); + }); + win.onRestored.addListener(function() { + eventCounts['onRestored']++; + if (eventCallback) + eventCallback(); + }); +}); + diff --git a/chrome/test/data/extensions/platform_apps/windows_api_properties/main.html b/chrome/test/data/extensions/platform_apps/windows_api_properties/main.html new file mode 100644 index 0000000..ee7be70 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/windows_api_properties/main.html @@ -0,0 +1 @@ +<script src="main.js"></script> diff --git a/chrome/test/data/extensions/platform_apps/windows_api_properties/main.js b/chrome/test/data/extensions/platform_apps/windows_api_properties/main.js new file mode 100644 index 0000000..d469581 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/windows_api_properties/main.js @@ -0,0 +1,57 @@ +// 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. + +var current = chrome.app.window.current(); +var bg = null; +var nextTestNumber = 1; + +function makeEventTest(eventName, startFunction) { + var test = function() { + bg.clearEventCounts(); + var listener = function() { + current[eventName].removeListener(listener); + function waitForBackgroundPageToSeeEvent() { + if (!bg.eventCounts[eventName] > 0) { + bg.eventCallback = waitForBackgroundPageToSeeEvent; + } + else { + bg.eventCallback = null; + current.restore(); + chrome.test.succeed(); + } + } + waitForBackgroundPageToSeeEvent(); + }; + current[eventName].addListener(listener); + startFunction(); + }; + // For anonymous functions, setting 'generatedName' controls what shows up in + // the apitest framework's logging output. + test.generatedName = "Test" + nextTestNumber++ + "_" + eventName; + return test; +} + + +var tests = [ + + makeEventTest('onMinimized', function() { current.minimize(); }), + makeEventTest('onMaximized', function() { current.maximize(); }), + makeEventTest('onRestored', function() { + current.minimize(); + current.restore(); + }), + makeEventTest('onRestored', function() { + current.maximize(); + current.restore(); + }), + makeEventTest('onBoundsChanged', function() { + current.setBounds({left:5, top:5, width:100, height:100}); + }) + +]; + +chrome.runtime.getBackgroundPage(function(page) { + bg = page; + chrome.test.runTests(tests); +}); diff --git a/chrome/test/data/extensions/platform_apps/windows_api_properties/manifest.json b/chrome/test/data/extensions/platform_apps/windows_api_properties/manifest.json new file mode 100644 index 0000000..ce09a2d --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/windows_api_properties/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "app.windows properties", + "version": "1", + "app": { + "background": { + "scripts": ["background.js"] + } + } +} |