1 // Copyright (c) 2012 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 "ash/shell/window_type_launcher.h" 6 7 #include "ash/root_window_controller.h" 8 #include "ash/screensaver/screensaver_view.h" 9 #include "ash/session/session_state_delegate.h" 10 #include "ash/shelf/shelf_widget.h" 11 #include "ash/shell.h" 12 #include "ash/shell/example_factory.h" 13 #include "ash/shell/panel_window.h" 14 #include "ash/shell/toplevel_window.h" 15 #include "ash/shell_delegate.h" 16 #include "ash/shell_window_ids.h" 17 #include "ash/system/status_area_widget.h" 18 #include "ash/system/web_notification/web_notification_tray.h" 19 #include "ash/test/child_modal_window.h" 20 #include "base/bind.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "base/time/time.h" 23 #include "content/public/browser/browser_thread.h" 24 #include "ui/aura/window.h" 25 #include "ui/aura/window_event_dispatcher.h" 26 #include "ui/compositor/layer.h" 27 #include "ui/gfx/canvas.h" 28 #include "ui/message_center/message_center.h" 29 #include "ui/message_center/notification_types.h" 30 #include "ui/views/controls/button/label_button.h" 31 #include "ui/views/controls/menu/menu_item_view.h" 32 #include "ui/views/controls/menu/menu_runner.h" 33 #include "ui/views/examples/examples_window_with_content.h" 34 #include "ui/views/layout/grid_layout.h" 35 #include "ui/views/widget/widget.h" 36 #include "ui/wm/core/shadow_types.h" 37 38 using views::MenuItemView; 39 using views::MenuRunner; 40 41 namespace ash { 42 namespace shell { 43 44 namespace { 45 46 SkColor g_colors[] = { SK_ColorRED, 47 SK_ColorYELLOW, 48 SK_ColorBLUE, 49 SK_ColorGREEN }; 50 int g_color_index = 0; 51 52 class ModalWindow : public views::WidgetDelegateView, 53 public views::ButtonListener { 54 public: 55 explicit ModalWindow(ui::ModalType modal_type) 56 : modal_type_(modal_type), 57 color_(g_colors[g_color_index]), 58 open_button_(new views::LabelButton(this, 59 base::ASCIIToUTF16("Moar!"))) { 60 ++g_color_index %= arraysize(g_colors); 61 open_button_->SetStyle(views::Button::STYLE_BUTTON); 62 AddChildView(open_button_); 63 } 64 virtual ~ModalWindow() { 65 } 66 67 static void OpenModalWindow(aura::Window* parent, ui::ModalType modal_type) { 68 views::Widget* widget = 69 views::Widget::CreateWindowWithParent(new ModalWindow(modal_type), 70 parent); 71 widget->GetNativeView()->SetName("ModalWindow"); 72 widget->Show(); 73 } 74 75 // Overridden from views::View: 76 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 77 canvas->FillRect(GetLocalBounds(), color_); 78 } 79 virtual gfx::Size GetPreferredSize() const OVERRIDE { 80 return gfx::Size(200, 200); 81 } 82 virtual void Layout() OVERRIDE { 83 gfx::Size open_ps = open_button_->GetPreferredSize(); 84 gfx::Rect local_bounds = GetLocalBounds(); 85 open_button_->SetBounds( 86 5, local_bounds.bottom() - open_ps.height() - 5, 87 open_ps.width(), open_ps.height()); 88 } 89 90 // Overridden from views::WidgetDelegate: 91 virtual views::View* GetContentsView() OVERRIDE { 92 return this; 93 } 94 virtual bool CanResize() const OVERRIDE { 95 return true; 96 } 97 virtual base::string16 GetWindowTitle() const OVERRIDE { 98 return base::ASCIIToUTF16("Modal Window"); 99 } 100 virtual ui::ModalType GetModalType() const OVERRIDE { 101 return modal_type_; 102 } 103 104 // Overridden from views::ButtonListener: 105 virtual void ButtonPressed(views::Button* sender, 106 const ui::Event& event) OVERRIDE { 107 DCHECK(sender == open_button_); 108 OpenModalWindow(GetWidget()->GetNativeView(), modal_type_); 109 } 110 111 private: 112 ui::ModalType modal_type_; 113 SkColor color_; 114 views::LabelButton* open_button_; 115 116 DISALLOW_COPY_AND_ASSIGN(ModalWindow); 117 }; 118 119 class NonModalTransient : public views::WidgetDelegateView { 120 public: 121 NonModalTransient() 122 : color_(g_colors[g_color_index]) { 123 ++g_color_index %= arraysize(g_colors); 124 } 125 virtual ~NonModalTransient() { 126 } 127 128 static void OpenNonModalTransient(aura::Window* parent) { 129 views::Widget* widget = 130 views::Widget::CreateWindowWithParent(new NonModalTransient, parent); 131 widget->GetNativeView()->SetName("NonModalTransient"); 132 widget->Show(); 133 } 134 135 static void ToggleNonModalTransient(aura::Window* parent) { 136 if (!non_modal_transient_) { 137 non_modal_transient_ = 138 views::Widget::CreateWindowWithParent(new NonModalTransient, parent); 139 non_modal_transient_->GetNativeView()->SetName("NonModalTransient"); 140 } 141 if (non_modal_transient_->IsVisible()) 142 non_modal_transient_->Hide(); 143 else 144 non_modal_transient_->Show(); 145 } 146 147 // Overridden from views::View: 148 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 149 canvas->FillRect(GetLocalBounds(), color_); 150 } 151 virtual gfx::Size GetPreferredSize() const OVERRIDE { 152 return gfx::Size(250, 250); 153 } 154 155 // Overridden from views::WidgetDelegate: 156 virtual views::View* GetContentsView() OVERRIDE { 157 return this; 158 } 159 virtual bool CanResize() const OVERRIDE { 160 return true; 161 } 162 virtual base::string16 GetWindowTitle() const OVERRIDE { 163 return base::ASCIIToUTF16("Non-Modal Transient"); 164 } 165 virtual void DeleteDelegate() OVERRIDE { 166 if (GetWidget() == non_modal_transient_) 167 non_modal_transient_ = NULL; 168 169 delete this; 170 } 171 172 private: 173 SkColor color_; 174 175 static views::Widget* non_modal_transient_; 176 177 DISALLOW_COPY_AND_ASSIGN(NonModalTransient); 178 }; 179 180 // static 181 views::Widget* NonModalTransient::non_modal_transient_ = NULL; 182 183 void AddViewToLayout(views::GridLayout* layout, views::View* view) { 184 layout->StartRow(0, 0); 185 layout->AddView(view); 186 layout->AddPaddingRow(0, 5); 187 } 188 189 } // namespace 190 191 void InitWindowTypeLauncher() { 192 views::Widget* widget = 193 views::Widget::CreateWindowWithContextAndBounds( 194 new WindowTypeLauncher, 195 Shell::GetPrimaryRootWindow(), 196 gfx::Rect(120, 150, 300, 410)); 197 widget->GetNativeView()->SetName("WindowTypeLauncher"); 198 wm::SetShadowType(widget->GetNativeView(), 199 wm::SHADOW_TYPE_RECTANGULAR); 200 widget->Show(); 201 } 202 203 WindowTypeLauncher::WindowTypeLauncher() 204 : create_button_(new views::LabelButton( 205 this, base::ASCIIToUTF16("Create Window"))), 206 panel_button_(new views::LabelButton( 207 this, base::ASCIIToUTF16("Create Panel"))), 208 create_nonresizable_button_(new views::LabelButton( 209 this, base::ASCIIToUTF16("Create Non-Resizable Window"))), 210 bubble_button_(new views::LabelButton( 211 this, base::ASCIIToUTF16("Create Pointy Bubble"))), 212 lock_button_(new views::LabelButton( 213 this, base::ASCIIToUTF16("Lock Screen"))), 214 widgets_button_(new views::LabelButton( 215 this, base::ASCIIToUTF16("Show Example Widgets"))), 216 system_modal_button_(new views::LabelButton( 217 this, base::ASCIIToUTF16("Open System Modal Window"))), 218 window_modal_button_(new views::LabelButton( 219 this, base::ASCIIToUTF16("Open Window Modal Window"))), 220 child_modal_button_(new views::LabelButton( 221 this, base::ASCIIToUTF16("Open Child Modal Window"))), 222 transient_button_(new views::LabelButton( 223 this, base::ASCIIToUTF16("Open Non-Modal Transient Window"))), 224 examples_button_(new views::LabelButton( 225 this, base::ASCIIToUTF16("Open Views Examples Window"))), 226 show_hide_window_button_(new views::LabelButton( 227 this, base::ASCIIToUTF16("Show/Hide a Window"))), 228 show_screensaver_(new views::LabelButton( 229 this, base::ASCIIToUTF16("Show the Screensaver [for 5 seconds]"))), 230 show_web_notification_(new views::LabelButton( 231 this, base::ASCIIToUTF16("Show a web/app notification"))) { 232 create_button_->SetStyle(views::Button::STYLE_BUTTON); 233 panel_button_->SetStyle(views::Button::STYLE_BUTTON); 234 create_nonresizable_button_->SetStyle(views::Button::STYLE_BUTTON); 235 bubble_button_->SetStyle(views::Button::STYLE_BUTTON); 236 lock_button_->SetStyle(views::Button::STYLE_BUTTON); 237 widgets_button_->SetStyle(views::Button::STYLE_BUTTON); 238 system_modal_button_->SetStyle(views::Button::STYLE_BUTTON); 239 window_modal_button_->SetStyle(views::Button::STYLE_BUTTON); 240 child_modal_button_->SetStyle(views::Button::STYLE_BUTTON); 241 transient_button_->SetStyle(views::Button::STYLE_BUTTON); 242 examples_button_->SetStyle(views::Button::STYLE_BUTTON); 243 show_hide_window_button_->SetStyle(views::Button::STYLE_BUTTON); 244 show_screensaver_->SetStyle(views::Button::STYLE_BUTTON); 245 show_web_notification_->SetStyle(views::Button::STYLE_BUTTON); 246 247 views::GridLayout* layout = new views::GridLayout(this); 248 layout->SetInsets(5, 5, 5, 5); 249 SetLayoutManager(layout); 250 views::ColumnSet* column_set = layout->AddColumnSet(0); 251 column_set->AddColumn(views::GridLayout::LEADING, 252 views::GridLayout::CENTER, 253 0, 254 views::GridLayout::USE_PREF, 255 0, 256 0); 257 AddViewToLayout(layout, create_button_); 258 AddViewToLayout(layout, panel_button_); 259 AddViewToLayout(layout, create_nonresizable_button_); 260 AddViewToLayout(layout, bubble_button_); 261 AddViewToLayout(layout, lock_button_); 262 AddViewToLayout(layout, widgets_button_); 263 AddViewToLayout(layout, system_modal_button_); 264 AddViewToLayout(layout, window_modal_button_); 265 AddViewToLayout(layout, child_modal_button_); 266 AddViewToLayout(layout, transient_button_); 267 AddViewToLayout(layout, examples_button_); 268 AddViewToLayout(layout, show_hide_window_button_); 269 AddViewToLayout(layout, show_screensaver_); 270 AddViewToLayout(layout, show_web_notification_); 271 set_context_menu_controller(this); 272 } 273 274 WindowTypeLauncher::~WindowTypeLauncher() { 275 } 276 277 void WindowTypeLauncher::OnPaint(gfx::Canvas* canvas) { 278 canvas->FillRect(GetLocalBounds(), SK_ColorWHITE); 279 } 280 281 bool WindowTypeLauncher::OnMousePressed(const ui::MouseEvent& event) { 282 // Overridden so we get OnMouseReleased and can show the context menu. 283 return true; 284 } 285 286 views::View* WindowTypeLauncher::GetContentsView() { 287 return this; 288 } 289 290 bool WindowTypeLauncher::CanResize() const { 291 return true; 292 } 293 294 base::string16 WindowTypeLauncher::GetWindowTitle() const { 295 return base::ASCIIToUTF16("Examples: Window Builder"); 296 } 297 298 bool WindowTypeLauncher::CanMaximize() const { 299 return true; 300 } 301 302 bool WindowTypeLauncher::CanMinimize() const { 303 return true; 304 } 305 306 void WindowTypeLauncher::ButtonPressed(views::Button* sender, 307 const ui::Event& event) { 308 if (sender == create_button_) { 309 ToplevelWindow::CreateParams params; 310 params.can_resize = true; 311 params.can_maximize = true; 312 ToplevelWindow::CreateToplevelWindow(params); 313 } else if (sender == panel_button_) { 314 PanelWindow::CreatePanelWindow(gfx::Rect()); 315 } else if (sender == create_nonresizable_button_) { 316 ToplevelWindow::CreateToplevelWindow(ToplevelWindow::CreateParams()); 317 } else if (sender == bubble_button_) { 318 CreatePointyBubble(sender); 319 } else if (sender == lock_button_) { 320 Shell::GetInstance()->session_state_delegate()->LockScreen(); 321 } else if (sender == widgets_button_) { 322 CreateWidgetsWindow(); 323 } else if (sender == system_modal_button_) { 324 ModalWindow::OpenModalWindow(GetWidget()->GetNativeView(), 325 ui::MODAL_TYPE_SYSTEM); 326 } else if (sender == window_modal_button_) { 327 ModalWindow::OpenModalWindow(GetWidget()->GetNativeView(), 328 ui::MODAL_TYPE_WINDOW); 329 } else if (sender == child_modal_button_) { 330 ash::test::CreateChildModalParent( 331 GetWidget()->GetNativeView()->GetRootWindow()); 332 } else if (sender == transient_button_) { 333 NonModalTransient::OpenNonModalTransient(GetWidget()->GetNativeView()); 334 } else if (sender == show_hide_window_button_) { 335 NonModalTransient::ToggleNonModalTransient(GetWidget()->GetNativeView()); 336 } else if (sender == show_screensaver_) { 337 ash::ShowScreensaver(GURL("http://www.google.com")); 338 content::BrowserThread::PostDelayedTask(content::BrowserThread::UI, 339 FROM_HERE, 340 base::Bind(&ash::CloseScreensaver), 341 base::TimeDelta::FromSeconds(5)); 342 343 } else if (sender == show_web_notification_) { 344 scoped_ptr<message_center::Notification> notification; 345 notification.reset(new message_center::Notification( 346 message_center::NOTIFICATION_TYPE_SIMPLE, 347 "id0", 348 base::ASCIIToUTF16("Test Shell Web Notification"), 349 base::ASCIIToUTF16("Notification message body."), 350 gfx::Image(), 351 base::ASCIIToUTF16("www.testshell.org"), 352 message_center::NotifierId( 353 message_center::NotifierId::APPLICATION, "test-id"), 354 message_center::RichNotificationData(), 355 NULL /* delegate */)); 356 357 ash::Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget() 358 ->web_notification_tray()->message_center() 359 ->AddNotification(notification.Pass()); 360 } else if (sender == examples_button_) { 361 views::examples::ShowExamplesWindowWithContent( 362 views::examples::DO_NOTHING_ON_CLOSE, 363 Shell::GetInstance()->delegate()->GetActiveBrowserContext(), 364 NULL); 365 } 366 } 367 368 void WindowTypeLauncher::ExecuteCommand(int id, int event_flags) { 369 switch (id) { 370 case COMMAND_NEW_WINDOW: 371 InitWindowTypeLauncher(); 372 break; 373 case COMMAND_TOGGLE_FULLSCREEN: 374 GetWidget()->SetFullscreen(!GetWidget()->IsFullscreen()); 375 break; 376 default: 377 break; 378 } 379 } 380 381 void WindowTypeLauncher::ShowContextMenuForView( 382 views::View* source, 383 const gfx::Point& point, 384 ui::MenuSourceType source_type) { 385 MenuItemView* root = new MenuItemView(this); 386 root->AppendMenuItem(COMMAND_NEW_WINDOW, 387 base::ASCIIToUTF16("New Window"), 388 MenuItemView::NORMAL); 389 root->AppendMenuItem(COMMAND_TOGGLE_FULLSCREEN, 390 base::ASCIIToUTF16("Toggle FullScreen"), 391 MenuItemView::NORMAL); 392 // MenuRunner takes ownership of root. 393 menu_runner_.reset(new MenuRunner( 394 root, MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU)); 395 if (menu_runner_->RunMenuAt(GetWidget(), 396 NULL, 397 gfx::Rect(point, gfx::Size()), 398 views::MENU_ANCHOR_TOPLEFT, 399 source_type) == MenuRunner::MENU_DELETED) { 400 return; 401 } 402 } 403 404 } // namespace shell 405 } // namespace ash 406