diff --git a/apps/app_restore_service.cc b/apps/app_restore_service.cc
index 683718afe30235..66f2a73bf90754 100644
--- a/apps/app_restore_service.cc
+++ b/apps/app_restore_service.cc
@@ -18,6 +18,10 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
+#if defined(OS_WIN)
+#include "win8/util/win8_util.h"
+#endif
+
using extensions::AppEventRouter;
using extensions::Extension;
using extensions::ExtensionHost;
@@ -26,6 +30,20 @@ using extensions::ExtensionSystem;
namespace apps {
+// static
+bool AppRestoreService::ShouldRestoreApps(bool is_browser_restart) {
+ bool should_restore_apps = is_browser_restart;
+#if defined(OS_CHROMEOS)
+ // Chromeos always restarts apps, even if it was a regular shutdown.
+ should_restore_apps = true;
+#elif defined(OS_WIN)
+ // Packaged apps are not supported in Metro mode, so don't try to start them.
+ if (win8::IsSingleWindowMetroMode())
+ should_restore_apps = false;
+#endif
+ return should_restore_apps;
+}
+
AppRestoreService::AppRestoreService(Profile* profile)
: profile_(profile) {
registrar_.Add(
diff --git a/apps/app_restore_service.h b/apps/app_restore_service.h
index a308c316f4a78d..f27c83cadec672 100644
--- a/apps/app_restore_service.h
+++ b/apps/app_restore_service.h
@@ -31,6 +31,10 @@ namespace apps {
class AppRestoreService : public ProfileKeyedService,
public content::NotificationObserver {
public:
+ // Returns true if apps should be restored on the current platform, given
+ // whether this new browser process launched due to a restart.
+ static bool ShouldRestoreApps(bool is_browser_restart);
+
explicit AppRestoreService(Profile* profile);
// Restart apps that need to be restarted and clear the "running" preference
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 2ebccb876e9aec..b4ac7f52ec24c2 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -14920,6 +14920,10 @@ Some features may be unavailable. Please check that the profile exists and you
desc="Infobar button 'no' text to cancel prompt to relaunch in deskop mode to use Chrome Apps">
No, stay in Windows 8 mode
+
+ Relaunching in Windows 8 mode will close your Chrome apps.
+
diff --git a/chrome/browser/extensions/shell_window_registry.cc b/chrome/browser/extensions/shell_window_registry.cc
index f7495f83e8a41d..2b5d3b0212b711 100644
--- a/chrome/browser/extensions/shell_window_registry.cc
+++ b/chrome/browser/extensions/shell_window_registry.cc
@@ -52,7 +52,7 @@ ShellWindowRegistry::~ShellWindowRegistry() {}
// static
ShellWindowRegistry* ShellWindowRegistry::Get(Profile* profile) {
- return Factory::GetForProfile(profile);
+ return Factory::GetForProfile(profile, true /* create */);
}
void ShellWindowRegistry::AddShellWindow(ShellWindow* shell_window) {
@@ -153,11 +153,13 @@ ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile(
gfx::NativeWindow window) {
std::vector profiles =
g_browser_process->profile_manager()->GetLoadedProfiles();
- for (std::vector::const_iterator i(profiles.begin());
- i < profiles.end(); ++i) {
- extensions::ShellWindowRegistry* registry =
- extensions::ShellWindowRegistry::Get(*i);
- DCHECK(registry);
+ for (std::vector::const_iterator i = profiles.begin();
+ i != profiles.end(); ++i) {
+ ShellWindowRegistry* registry = Factory::GetForProfile(*i,
+ false /* create */);
+ if (!registry)
+ continue;
+
ShellWindow* shell_window = registry->GetShellWindowForNativeWindow(window);
if (shell_window)
return shell_window;
@@ -166,6 +168,35 @@ ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile(
return NULL;
}
+// static
+bool ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
+ int window_type_mask) {
+ std::vector profiles =
+ g_browser_process->profile_manager()->GetLoadedProfiles();
+ for (std::vector::const_iterator i = profiles.begin();
+ i != profiles.end(); ++i) {
+ ShellWindowRegistry* registry = Factory::GetForProfile(*i,
+ false /* create */);
+ if (!registry)
+ continue;
+
+ const ShellWindowSet& shell_windows = registry->shell_windows();
+ if (shell_windows.empty())
+ continue;
+
+ if (window_type_mask == 0)
+ return true;
+
+ for (const_iterator j = shell_windows.begin(); j != shell_windows.end();
+ ++j) {
+ if ((*j)->window_type() & window_type_mask)
+ return true;
+ }
+ }
+
+ return false;
+}
+
void ShellWindowRegistry::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
@@ -192,9 +223,9 @@ void ShellWindowRegistry::Observe(int type,
// static
ShellWindowRegistry* ShellWindowRegistry::Factory::GetForProfile(
- Profile* profile) {
+ Profile* profile, bool create) {
return static_cast(
- GetInstance()->GetServiceForProfile(profile, true));
+ GetInstance()->GetServiceForProfile(profile, create));
}
ShellWindowRegistry::Factory* ShellWindowRegistry::Factory::GetInstance() {
diff --git a/chrome/browser/extensions/shell_window_registry.h b/chrome/browser/extensions/shell_window_registry.h
index 265ceeaca8d0e2..113a156ff4f595 100644
--- a/chrome/browser/extensions/shell_window_registry.h
+++ b/chrome/browser/extensions/shell_window_registry.h
@@ -94,6 +94,11 @@ class ShellWindowRegistry : public ProfileKeyedService,
static ShellWindow* GetShellWindowForNativeWindowAnyProfile(
gfx::NativeWindow window);
+ // Returns true if the number of shell windows registered across all profiles
+ // is non-zero. |window_type_mask| is a bitwise OR filter of
+ // ShellWindow::WindowType, or 0 for any window type.
+ static bool IsShellWindowRegisteredInAnyProfile(int window_type_mask);
+
protected:
// content::NotificationObserver:
virtual void Observe(int type,
@@ -103,7 +108,7 @@ class ShellWindowRegistry : public ProfileKeyedService,
private:
class Factory : public ProfileKeyedServiceFactory {
public:
- static ShellWindowRegistry* GetForProfile(Profile* profile);
+ static ShellWindowRegistry* GetForProfile(Profile* profile, bool create);
static Factory* GetInstance();
private:
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 87a53d3ed33eca..3ba57974675efd 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -46,6 +46,7 @@
#if defined(OS_WIN)
#include "base/win/metro.h"
#include "base/win/windows_version.h"
+#include "chrome/browser/ui/extensions/apps_metro_handler_win.h"
#endif
#if defined(USE_ASH)
@@ -87,17 +88,17 @@ bool HasInternalURL(const NavigationEntry* entry) {
// 6- If we are not the default exit.
//
// Note: this class deletes itself.
-class SwichToMetroUIHandler
+class SwitchToMetroUIHandler
: public ShellIntegration::DefaultWebClientObserver {
public:
- SwichToMetroUIHandler()
+ SwitchToMetroUIHandler()
: ALLOW_THIS_IN_INITIALIZER_LIST(default_browser_worker_(
new ShellIntegration::DefaultBrowserWorker(this))),
first_check_(true) {
default_browser_worker_->StartCheckIsDefault();
}
- virtual ~SwichToMetroUIHandler() {
+ virtual ~SwitchToMetroUIHandler() {
default_browser_worker_->ObserverDestroyed();
}
@@ -140,7 +141,7 @@ class SwichToMetroUIHandler
scoped_refptr default_browser_worker_;
bool first_check_;
- DISALLOW_COPY_AND_ASSIGN(SwichToMetroUIHandler);
+ DISALLOW_COPY_AND_ASSIGN(SwitchToMetroUIHandler);
};
#endif // defined(OS_WIN)
@@ -447,7 +448,11 @@ void BrowserCommandController::ExecuteCommandWithDisposition(
content::RecordAction(content::UserMetricsAction("Win8DesktopRestart"));
break;
case IDC_WIN8_METRO_RESTART:
- new SwichToMetroUIHandler;
+ if (!chrome::VerifySwitchToMetroForApps(window()->GetNativeWindow()))
+ break;
+
+ // SwitchToMetroUIHandler deletes itself.
+ new SwitchToMetroUIHandler;
content::RecordAction(content::UserMetricsAction("Win8MetroRestart"));
break;
#endif
diff --git a/chrome/browser/ui/cocoa/simple_message_box_mac.mm b/chrome/browser/ui/cocoa/simple_message_box_mac.mm
index a81d106f57cdec..088e49392e2f6e 100644
--- a/chrome/browser/ui/cocoa/simple_message_box_mac.mm
+++ b/chrome/browser/ui/cocoa/simple_message_box_mac.mm
@@ -17,6 +17,9 @@ MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
const string16& title,
const string16& message,
MessageBoxType type) {
+ if (type == MESSAGE_BOX_TYPE_OK_CANCEL)
+ NOTIMPLEMENTED();
+
startup_metric_utils::SetNonBrowserUIDisplayed();
// Ignore the title; it's the window title on other platforms and ignorable.
diff --git a/chrome/browser/ui/extensions/apps_metro_handler_win.cc b/chrome/browser/ui/extensions/apps_metro_handler_win.cc
new file mode 100644
index 00000000000000..125c8bf42b367e
--- /dev/null
+++ b/chrome/browser/ui/extensions/apps_metro_handler_win.cc
@@ -0,0 +1,31 @@
+// Copyright 2013 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.
+
+#include "chrome/browser/ui/extensions/apps_metro_handler_win.h"
+
+#include "chrome/browser/extensions/shell_window_registry.h"
+#include "chrome/browser/ui/extensions/shell_window.h"
+#include "chrome/browser/ui/simple_message_box.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace chrome {
+
+bool VerifySwitchToMetroForApps(gfx::NativeWindow parent_window) {
+ if (!extensions::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
+ ShellWindow::WINDOW_TYPE_DEFAULT)) {
+ return true;
+ }
+
+ MessageBoxResult result = ShowMessageBox(
+ parent_window,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+ l10n_util::GetStringUTF16(IDS_WIN8_PROMPT_TO_CLOSE_APPS_FOR_METRO),
+ MESSAGE_BOX_TYPE_OK_CANCEL);
+
+ return result == MESSAGE_BOX_RESULT_YES;
+}
+
+} // namespace chrome
diff --git a/chrome/browser/ui/extensions/apps_metro_handler_win.h b/chrome/browser/ui/extensions/apps_metro_handler_win.h
new file mode 100644
index 00000000000000..f1a79de9b606e3
--- /dev/null
+++ b/chrome/browser/ui/extensions/apps_metro_handler_win.h
@@ -0,0 +1,20 @@
+// Copyright 2013 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.
+
+#ifndef CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
+#define CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
+
+#include "ui/gfx/native_widget_types.h"
+
+namespace chrome {
+
+// Check if there are apps running and if not, return true. Otherwise, Show a
+// modal dialog on |parent| asking whether the user is OK with their packaged
+// apps closing, in order to relaunch to metro mode. Returns true if the user
+// clicks OK.
+bool VerifySwitchToMetroForApps(gfx::NativeWindow parent);
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
diff --git a/chrome/browser/ui/extensions/shell_window.h b/chrome/browser/ui/extensions/shell_window.h
index 932f6736d5574c..1654d543ad9dab 100644
--- a/chrome/browser/ui/extensions/shell_window.h
+++ b/chrome/browser/ui/extensions/shell_window.h
@@ -67,9 +67,10 @@ class ShellWindow : public content::NotificationObserver,
public extensions::ExtensionKeybindingRegistry::Delegate {
public:
enum WindowType {
- WINDOW_TYPE_DEFAULT, // Default shell window
- WINDOW_TYPE_PANEL, // OS controlled panel window (Ash only)
- WINDOW_TYPE_V1_PANEL, // For apps v1 support in Ash; deprecate with v1 apps
+ WINDOW_TYPE_DEFAULT = 1 << 0, // Default shell window.
+ WINDOW_TYPE_PANEL = 1 << 1, // OS controlled panel window (Ash only).
+ WINDOW_TYPE_V1_PANEL = 1 << 2, // For apps v1 support in Ash; deprecate
+ // with v1 apps.
};
enum Frame {
diff --git a/chrome/browser/ui/gtk/simple_message_box_gtk.cc b/chrome/browser/ui/gtk/simple_message_box_gtk.cc
index 703ab89e52cf18..3ce0150a5d8f6e 100644
--- a/chrome/browser/ui/gtk/simple_message_box_gtk.cc
+++ b/chrome/browser/ui/gtk/simple_message_box_gtk.cc
@@ -47,6 +47,9 @@ MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
const string16& title,
const string16& message,
MessageBoxType type) {
+ if (type == MESSAGE_BOX_TYPE_OK_CANCEL)
+ NOTIMPLEMENTED();
+
GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER;
GtkButtonsType gtk_buttons_type = GTK_BUTTONS_OK;
if (type == MESSAGE_BOX_TYPE_QUESTION) {
diff --git a/chrome/browser/ui/simple_message_box.h b/chrome/browser/ui/simple_message_box.h
index 9169066de20bca..46cea98f8b23a0 100644
--- a/chrome/browser/ui/simple_message_box.h
+++ b/chrome/browser/ui/simple_message_box.h
@@ -11,20 +11,20 @@
namespace chrome {
enum MessageBoxResult {
- MESSAGE_BOX_RESULT_NO = 0,
- MESSAGE_BOX_RESULT_YES = 1,
+ MESSAGE_BOX_RESULT_NO = 0, // User chose NO or CANCEL.
+ MESSAGE_BOX_RESULT_YES = 1, // User chose YES or OK.
};
enum MessageBoxType {
- MESSAGE_BOX_TYPE_INFORMATION,
- MESSAGE_BOX_TYPE_WARNING,
- MESSAGE_BOX_TYPE_QUESTION,
+ MESSAGE_BOX_TYPE_INFORMATION, // Shows an OK button.
+ MESSAGE_BOX_TYPE_WARNING, // Shows an OK button.
+ MESSAGE_BOX_TYPE_QUESTION, // Shows YES and NO buttons.
+ MESSAGE_BOX_TYPE_OK_CANCEL, // Shows OK and CANCEL buttons (Windows only).
};
// Shows a dialog box with the given |title| and |message|. If |parent| is
// non-NULL, the box will be made modal to the |parent|, except on Mac, where it
-// is always app-modal. If |type| is MESSAGE_BOX_TYPE_QUESTION, the box will
-// have YES and NO buttons; otherwise it will have an OK button.
+// is always app-modal.
//
// NOTE: In general, you should avoid this since it's usually poor UI.
// We have a variety of other surfaces such as wrench menu notifications and
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index b03cc55cf136cf..4eec6c8763e001 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -647,17 +647,14 @@ bool StartupBrowserCreatorImpl::ProcessStartupURLs(
else if (pref.type == SessionStartupPref::DEFAULT)
VLOG(1) << "Pref: default";
- apps::AppRestoreService* service =
+ apps::AppRestoreService* restore_service =
apps::AppRestoreServiceFactory::GetForProfile(profile_);
// NULL in incognito mode.
- if (service) {
- bool should_restore_apps = StartupBrowserCreator::WasRestarted();
-#if defined(OS_CHROMEOS)
- // Chromeos always restarts apps, even if it was a regular shutdown.
- should_restore_apps = true;
-#endif
- service->HandleStartup(should_restore_apps);
+ if (restore_service) {
+ restore_service->HandleStartup(apps::AppRestoreService::ShouldRestoreApps(
+ StartupBrowserCreator::WasRestarted()));
}
+
if (pref.type == SessionStartupPref::LAST) {
if (profile_->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
!command_line_.HasSwitch(switches::kRestoreLastSession)) {
diff --git a/chrome/browser/ui/views/simple_message_box_views.cc b/chrome/browser/ui/views/simple_message_box_views.cc
index 2faa66fc88f0f2..fcda39e81fecaf 100644
--- a/chrome/browser/ui/views/simple_message_box_views.cc
+++ b/chrome/browser/ui/views/simple_message_box_views.cc
@@ -91,8 +91,11 @@ SimpleMessageBoxViews::SimpleMessageBoxViews(const string16& title,
}
int SimpleMessageBoxViews::GetDialogButtons() const {
- if (type_ == MESSAGE_BOX_TYPE_QUESTION)
+ if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
+ type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+ }
+
return ui::DIALOG_BUTTON_OK;
}
@@ -103,6 +106,12 @@ string16 SimpleMessageBoxViews::GetDialogButtonLabel(
IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL :
IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
}
+
+ if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
+ return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
+ IDS_OK : IDS_CANCEL);
+ }
+
return l10n_util::GetStringUTF16(IDS_OK);
}
diff --git a/chrome/browser/ui/views/simple_message_box_win.cc b/chrome/browser/ui/views/simple_message_box_win.cc
index 861384ea186564..167600caa626a1 100644
--- a/chrome/browser/ui/views/simple_message_box_win.cc
+++ b/chrome/browser/ui/views/simple_message_box_win.cc
@@ -20,11 +20,18 @@ MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
parent = ui::GetWindowToParentTo(true);
UINT flags = MB_SETFOREGROUND;
- flags |= ((type == MESSAGE_BOX_TYPE_QUESTION) ? MB_YESNO : MB_OK);
+ if (type == MESSAGE_BOX_TYPE_QUESTION) {
+ flags |= MB_YESNO;
+ } else if (type == MESSAGE_BOX_TYPE_OK_CANCEL) {
+ flags |= MB_OKCANCEL;
+ } else {
+ flags |= MB_OK;
+ }
flags |= ((type == MESSAGE_BOX_TYPE_INFORMATION) ?
MB_ICONINFORMATION : MB_ICONWARNING);
- return (ui::MessageBox(parent, message, title, flags) == IDNO) ?
- MESSAGE_BOX_RESULT_NO : MESSAGE_BOX_RESULT_YES;
+ int result = ui::MessageBox(parent, message, title, flags);
+ return (result == IDYES || result == IDOK) ?
+ MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO;
}
} // namespace chrome
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index bc3b67afd44076..29d955845fb9e4 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -868,6 +868,8 @@
'browser/ui/extensions/app_metro_infobar_delegate_win.h',
'browser/ui/extensions/application_launch.cc',
'browser/ui/extensions/application_launch.h',
+ 'browser/ui/extensions/apps_metro_handler_win.cc',
+ 'browser/ui/extensions/apps_metro_handler_win.h',
'browser/ui/extensions/extension_install_ui_default.cc',
'browser/ui/extensions/extension_install_ui_default.h',
'browser/ui/extensions/extension_enable_flow.cc',