Home | History | Annotate | Download | only in apps
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h"
      6 
      7 #include "apps/app_window.h"
      8 #include "apps/app_window_registry.h"
      9 #include "apps/ui/views/app_window_frame_view.h"
     10 #include "ash/shell.h"
     11 #include "base/command_line.h"
     12 #include "base/file_util.h"
     13 #include "base/path_service.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/threading/sequenced_worker_pool.h"
     16 #include "chrome/browser/apps/per_app_settings_service.h"
     17 #include "chrome/browser/apps/per_app_settings_service_factory.h"
     18 #include "chrome/browser/jumplist_updater_win.h"
     19 #include "chrome/browser/metro_utils/metro_chrome_win.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/shell_integration.h"
     22 #include "chrome/browser/ui/views/apps/app_window_desktop_native_widget_aura_win.h"
     23 #include "chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h"
     24 #include "chrome/browser/web_applications/web_app.h"
     25 #include "chrome/browser/web_applications/web_app_win.h"
     26 #include "chrome/common/chrome_icon_resources_win.h"
     27 #include "chrome/common/chrome_switches.h"
     28 #include "content/public/browser/browser_thread.h"
     29 #include "extensions/browser/extension_util.h"
     30 #include "extensions/common/extension.h"
     31 #include "grit/generated_resources.h"
     32 #include "ui/aura/remote_window_tree_host_win.h"
     33 #include "ui/base/l10n/l10n_util.h"
     34 #include "ui/base/win/shell.h"
     35 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
     36 #include "ui/views/win/hwnd_util.h"
     37 
     38 ChromeNativeAppWindowViewsWin::ChromeNativeAppWindowViewsWin()
     39     : weak_ptr_factory_(this), glass_frame_view_(NULL) {
     40 }
     41 
     42 void ChromeNativeAppWindowViewsWin::ActivateParentDesktopIfNecessary() {
     43   // Only switching into Ash from Native is supported. Tearing the user out of
     44   // Metro mode can only be done by launching a process from Metro mode itself.
     45   // This is done for launching apps, but not regular activations.
     46   if (IsRunningInAsh() &&
     47       chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_NATIVE) {
     48     chrome::ActivateMetroChrome();
     49   }
     50 }
     51 
     52 HWND ChromeNativeAppWindowViewsWin::GetNativeAppWindowHWND() const {
     53   return views::HWNDForWidget(widget()->GetTopLevelWidget());
     54 }
     55 
     56 bool ChromeNativeAppWindowViewsWin::IsRunningInAsh() {
     57   if (!ash::Shell::HasInstance())
     58     return false;
     59 
     60   views::Widget* widget =
     61       implicit_cast<views::WidgetDelegate*>(this)->GetWidget();
     62   chrome::HostDesktopType host_desktop_type =
     63       chrome::GetHostDesktopTypeForNativeWindow(widget->GetNativeWindow());
     64   return host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH;
     65 }
     66 
     67 void ChromeNativeAppWindowViewsWin::EnsureCaptionStyleSet() {
     68   // Windows seems to have issues maximizing windows without WS_CAPTION.
     69   // The default views / Aura implementation will remove this if we are using
     70   // frameless or colored windows, so we put it back here.
     71   HWND hwnd = GetNativeAppWindowHWND();
     72   int current_style = ::GetWindowLong(hwnd, GWL_STYLE);
     73   ::SetWindowLong(hwnd, GWL_STYLE, current_style | WS_CAPTION);
     74 }
     75 
     76 void ChromeNativeAppWindowViewsWin::OnBeforeWidgetInit(
     77     views::Widget::InitParams* init_params,
     78     views::Widget* widget) {
     79   content::BrowserContext* browser_context = app_window()->browser_context();
     80   std::string extension_id = app_window()->extension_id();
     81   // If an app has any existing windows, ensure new ones are created on the
     82   // same desktop.
     83   apps::AppWindow* any_existing_window =
     84       apps::AppWindowRegistry::Get(browser_context)
     85           ->GetCurrentAppWindowForApp(extension_id);
     86   chrome::HostDesktopType desktop_type;
     87   if (any_existing_window) {
     88     desktop_type = chrome::GetHostDesktopTypeForNativeWindow(
     89         any_existing_window->GetNativeWindow());
     90   } else {
     91     PerAppSettingsService* settings =
     92         PerAppSettingsServiceFactory::GetForBrowserContext(browser_context);
     93     if (settings->HasDesktopLastLaunchedFrom(extension_id)) {
     94       desktop_type = settings->GetDesktopLastLaunchedFrom(extension_id);
     95     } else {
     96       // We don't know what desktop this app was last launched from, so take our
     97       // best guess as to what desktop the user is on.
     98       desktop_type = chrome::GetActiveDesktop();
     99     }
    100   }
    101   if (desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
    102     init_params->context = ash::Shell::GetPrimaryRootWindow();
    103   else
    104     init_params->native_widget = new AppWindowDesktopNativeWidgetAuraWin(this);
    105 }
    106 
    107 void ChromeNativeAppWindowViewsWin::InitializeDefaultWindow(
    108     const apps::AppWindow::CreateParams& create_params) {
    109   ChromeNativeAppWindowViews::InitializeDefaultWindow(create_params);
    110 
    111   const extensions::Extension* extension = app_window()->GetExtension();
    112   if (!extension)
    113     return;
    114 
    115   std::string app_name =
    116       web_app::GenerateApplicationNameFromExtensionId(extension->id());
    117   base::string16 app_name_wide = base::UTF8ToWide(app_name);
    118   HWND hwnd = GetNativeAppWindowHWND();
    119   Profile* profile =
    120       Profile::FromBrowserContext(app_window()->browser_context());
    121   app_model_id_ =
    122       ShellIntegration::GetAppModelIdForProfile(app_name_wide,
    123                                                 profile->GetPath());
    124   ui::win::SetAppIdForWindow(app_model_id_, hwnd);
    125 
    126   web_app::UpdateRelaunchDetailsForApp(profile, extension, hwnd);
    127 
    128   if (!create_params.transparent_background && !IsRunningInAsh())
    129     EnsureCaptionStyleSet();
    130   UpdateShelfMenu();
    131 }
    132 
    133 views::NonClientFrameView*
    134 ChromeNativeAppWindowViewsWin::CreateStandardDesktopAppFrame() {
    135   glass_frame_view_ = NULL;
    136   if (ui::win::IsAeroGlassEnabled()) {
    137     glass_frame_view_ = new GlassAppWindowFrameViewWin(this, widget());
    138     return glass_frame_view_;
    139   }
    140   return ChromeNativeAppWindowViews::CreateStandardDesktopAppFrame();
    141 }
    142 
    143 void ChromeNativeAppWindowViewsWin::Show() {
    144   ActivateParentDesktopIfNecessary();
    145   ChromeNativeAppWindowViews::Show();
    146 }
    147 
    148 void ChromeNativeAppWindowViewsWin::Activate() {
    149   ActivateParentDesktopIfNecessary();
    150   ChromeNativeAppWindowViews::Activate();
    151 }
    152 
    153 void ChromeNativeAppWindowViewsWin::UpdateShelfMenu() {
    154   if (!JumpListUpdater::IsEnabled())
    155     return;
    156 
    157   // Currently the only option is related to ephemeral apps, so avoid updating
    158   // the app's jump list when the feature is not enabled.
    159   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    160           switches::kEnableEphemeralApps)) {
    161     return;
    162   }
    163 
    164   const extensions::Extension* extension = app_window()->GetExtension();
    165   if (!extension)
    166     return;
    167 
    168   // For the icon resources.
    169   base::FilePath chrome_path;
    170   if (!PathService::Get(base::FILE_EXE, &chrome_path))
    171     return;
    172 
    173   JumpListUpdater jumplist_updater(app_model_id_);
    174   if (!jumplist_updater.BeginUpdate())
    175     return;
    176 
    177   // Add item to install ephemeral apps.
    178   if (extensions::util::IsEphemeralApp(extension->id(),
    179                                        app_window()->browser_context())) {
    180     scoped_refptr<ShellLinkItem> link(new ShellLinkItem());
    181     link->set_title(l10n_util::GetStringUTF16(IDS_APP_INSTALL_TITLE));
    182     link->set_icon(chrome_path.value(),
    183                    icon_resources::kInstallPackagedAppIndex);
    184     ShellIntegration::AppendProfileArgs(
    185         app_window()->browser_context()->GetPath(), link->GetCommandLine());
    186     link->GetCommandLine()->AppendSwitchASCII(switches::kInstallFromWebstore,
    187                                               extension->id());
    188 
    189     ShellLinkItemList items;
    190     items.push_back(link);
    191     jumplist_updater.AddTasks(items);
    192   }
    193 
    194   // Note that an empty jumplist must still be committed to clear all items.
    195   jumplist_updater.CommitUpdate();
    196 }
    197