| OLD | NEW |
| (Empty) |
| 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 "chrome/browser/ui/panels/panel_browser_window_gtk.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "chrome/browser/ui/browser.h" | |
| 9 #include "chrome/browser/ui/browser_list.h" | |
| 10 #include "chrome/browser/ui/browser_window.h" | |
| 11 #include "chrome/browser/ui/gtk/browser_titlebar.h" | |
| 12 #include "chrome/browser/ui/gtk/custom_button.h" | |
| 13 #include "chrome/browser/ui/gtk/gtk_theme_service.h" | |
| 14 #include "chrome/browser/ui/panels/panel.h" | |
| 15 #include "chrome/browser/ui/panels/panel_browser_titlebar_gtk.h" | |
| 16 #include "chrome/browser/ui/panels/panel_constants.h" | |
| 17 #include "chrome/browser/ui/panels/panel_drag_gtk.h" | |
| 18 #include "chrome/browser/ui/panels/panel_manager.h" | |
| 19 #include "chrome/browser/ui/panels/panel_strip.h" | |
| 20 #include "chrome/common/chrome_notification_types.h" | |
| 21 #include "content/public/browser/native_web_keyboard_event.h" | |
| 22 #include "content/public/browser/notification_service.h" | |
| 23 #include "grit/theme_resources.h" | |
| 24 #include "grit/ui_resources.h" | |
| 25 #include "ui/base/gtk/gtk_compat.h" | |
| 26 #include "ui/gfx/canvas.h" | |
| 27 #include "ui/gfx/image/cairo_cached_surface.h" | |
| 28 #include "ui/gfx/image/image.h" | |
| 29 | |
| 30 using content::NativeWebKeyboardEvent; | |
| 31 using content::WebContents; | |
| 32 | |
| 33 namespace { | |
| 34 | |
| 35 // Colors used to draw frame background under default theme. | |
| 36 const SkColor kActiveBackgroundDefaultColor = SkColorSetRGB(0x3a, 0x3d, 0x3d); | |
| 37 const SkColor kInactiveBackgroundDefaultColor = SkColorSetRGB(0x7a, 0x7c, 0x7c); | |
| 38 const SkColor kAttentionBackgroundDefaultColor = | |
| 39 SkColorSetRGB(0xff, 0xab, 0x57); | |
| 40 const SkColor kMinimizeBackgroundDefaultColor = SkColorSetRGB(0xf5, 0xf4, 0xf0); | |
| 41 const SkColor kMinimizeBorderDefaultColor = SkColorSetRGB(0xc9, 0xc9, 0xc9); | |
| 42 | |
| 43 // Color used to draw the divider line between the titlebar and the client area. | |
| 44 const SkColor kDividerColor = SkColorSetRGB(0x2a, 0x2c, 0x2c); | |
| 45 | |
| 46 // Set minimium width for window really small. | |
| 47 const int kMinWindowWidth = 26; | |
| 48 | |
| 49 gfx::Image* CreateImageForColor(SkColor color) { | |
| 50 gfx::Canvas canvas(gfx::Size(1, 1), ui::SCALE_FACTOR_100P, true); | |
| 51 canvas.DrawColor(color); | |
| 52 return new gfx::Image(gfx::ImageSkia(canvas.ExtractImageRep())); | |
| 53 } | |
| 54 | |
| 55 const gfx::Image* GetActiveBackgroundDefaultImage() { | |
| 56 static gfx::Image* image = NULL; | |
| 57 if (!image) | |
| 58 image = CreateImageForColor(kActiveBackgroundDefaultColor); | |
| 59 return image; | |
| 60 } | |
| 61 | |
| 62 const gfx::Image* GetInactiveBackgroundDefaultImage() { | |
| 63 static gfx::Image* image = NULL; | |
| 64 if (!image) | |
| 65 image = CreateImageForColor(kInactiveBackgroundDefaultColor); | |
| 66 return image; | |
| 67 } | |
| 68 | |
| 69 const gfx::Image* GetAttentionBackgroundDefaultImage() { | |
| 70 static gfx::Image* image = NULL; | |
| 71 if (!image) | |
| 72 image = CreateImageForColor(kAttentionBackgroundDefaultColor); | |
| 73 return image; | |
| 74 } | |
| 75 | |
| 76 const gfx::Image* GetMinimizeBackgroundDefaultImage() { | |
| 77 static gfx::Image* image = NULL; | |
| 78 if (!image) | |
| 79 image = CreateImageForColor(kMinimizeBackgroundDefaultColor); | |
| 80 return image; | |
| 81 } | |
| 82 | |
| 83 } // namespace | |
| 84 | |
| 85 NativePanel* Panel::CreateNativePanel(Browser* browser, Panel* panel, | |
| 86 const gfx::Rect& bounds) { | |
| 87 PanelBrowserWindowGtk* panel_browser_window_gtk = | |
| 88 new PanelBrowserWindowGtk(browser, panel, bounds); | |
| 89 panel_browser_window_gtk->Init(); | |
| 90 return panel_browser_window_gtk; | |
| 91 } | |
| 92 | |
| 93 PanelBrowserWindowGtk::PanelBrowserWindowGtk(Browser* browser, | |
| 94 Panel* panel, | |
| 95 const gfx::Rect& bounds) | |
| 96 : BrowserWindowGtk(browser), | |
| 97 panel_(panel), | |
| 98 bounds_(bounds), | |
| 99 paint_state_(PAINT_AS_INACTIVE), | |
| 100 is_drawing_attention_(false) { | |
| 101 } | |
| 102 | |
| 103 PanelBrowserWindowGtk::~PanelBrowserWindowGtk() { | |
| 104 } | |
| 105 | |
| 106 void PanelBrowserWindowGtk::Init() { | |
| 107 BrowserWindowGtk::Init(); | |
| 108 | |
| 109 // Keep the window always on top. | |
| 110 gtk_window_set_keep_above(window(), TRUE); | |
| 111 | |
| 112 // Show the window on all the virtual desktops. | |
| 113 gtk_window_stick(window()); | |
| 114 | |
| 115 // Do not show an icon in the task bar. Window operations such as close, | |
| 116 // minimize etc. can only be done from the panel UI. | |
| 117 gtk_window_set_skip_taskbar_hint(window(), TRUE); | |
| 118 | |
| 119 // Only need to watch for titlebar button release event. BrowserWindowGtk | |
| 120 // already watches for button-press-event and determines if titlebar or | |
| 121 // window edge was hit. | |
| 122 g_signal_connect(titlebar_widget(), "button-release-event", | |
| 123 G_CALLBACK(OnTitlebarButtonReleaseEventThunk), this); | |
| 124 | |
| 125 registrar_.Add( | |
| 126 this, | |
| 127 chrome::NOTIFICATION_WINDOW_CLOSED, | |
| 128 content::Source<GtkWindow>(window())); | |
| 129 } | |
| 130 | |
| 131 BrowserTitlebarBase* PanelBrowserWindowGtk::CreateBrowserTitlebar() { | |
| 132 return new PanelBrowserTitlebarGtk(this, window()); | |
| 133 } | |
| 134 | |
| 135 PanelBrowserTitlebarGtk* PanelBrowserWindowGtk::GetPanelTitlebar() const { | |
| 136 return static_cast<PanelBrowserTitlebarGtk*>(titlebar()); | |
| 137 } | |
| 138 | |
| 139 bool PanelBrowserWindowGtk::UsingDefaultTheme() const { | |
| 140 // No theme is provided for attention painting. | |
| 141 if (paint_state_ == PAINT_FOR_ATTENTION) | |
| 142 return true; | |
| 143 | |
| 144 GtkThemeService* theme_provider = GtkThemeService::GetFrom(panel_->profile()); | |
| 145 return theme_provider->UsingDefaultTheme() || | |
| 146 theme_provider->UsingNativeTheme(); | |
| 147 } | |
| 148 | |
| 149 bool PanelBrowserWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) { | |
| 150 // Only detect the window edge when panels can be resized by the user. | |
| 151 // This method is used by the base class to detect when the cursor has | |
| 152 // hit the window edge in order to change the cursor to a resize cursor | |
| 153 // and to detect when to initiate a resize drag. | |
| 154 panel::Resizability resizability = panel_->CanResizeByMouse(); | |
| 155 if (panel::NOT_RESIZABLE == resizability) | |
| 156 return false; | |
| 157 | |
| 158 if (!BrowserWindowGtk::GetWindowEdge(x, y, edge)) | |
| 159 return FALSE; | |
| 160 | |
| 161 // Special handling if bottom edge is not resizable. | |
| 162 if (panel::RESIZABLE_ALL_SIDES_EXCEPT_BOTTOM == resizability) { | |
| 163 if (*edge == GDK_WINDOW_EDGE_SOUTH) | |
| 164 return FALSE; | |
| 165 if (*edge == GDK_WINDOW_EDGE_SOUTH_WEST) | |
| 166 *edge = GDK_WINDOW_EDGE_WEST; | |
| 167 else if (*edge == GDK_WINDOW_EDGE_SOUTH_EAST) | |
| 168 *edge = GDK_WINDOW_EDGE_EAST; | |
| 169 } | |
| 170 | |
| 171 return TRUE; | |
| 172 } | |
| 173 | |
| 174 GdkRegion* PanelBrowserWindowGtk::GetWindowShape(int width, int height) const { | |
| 175 // For panels, only top corners are rounded. The bottom corners are not | |
| 176 // rounded because panels are aligned to the bottom edge of the screen. | |
| 177 GdkRectangle top_top_rect = { 3, 0, width - 6, 1 }; | |
| 178 GdkRectangle top_mid_rect = { 1, 1, width - 2, 2 }; | |
| 179 GdkRectangle mid_rect = { 0, 3, width, height - 3 }; | |
| 180 GdkRegion* mask = gdk_region_rectangle(&top_top_rect); | |
| 181 gdk_region_union_with_rect(mask, &top_mid_rect); | |
| 182 gdk_region_union_with_rect(mask, &mid_rect); | |
| 183 return mask; | |
| 184 } | |
| 185 | |
| 186 bool PanelBrowserWindowGtk::UseCustomFrame() const { | |
| 187 // We always use custom frame for panels. | |
| 188 return true; | |
| 189 } | |
| 190 | |
| 191 void PanelBrowserWindowGtk::DrawFrame(GtkWidget* widget, | |
| 192 GdkEventExpose* event) { | |
| 193 cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget)); | |
| 194 gdk_cairo_rectangle(cr, &event->area); | |
| 195 cairo_clip(cr); | |
| 196 | |
| 197 // Update the painting state. | |
| 198 int window_height = gdk_window_get_height(gtk_widget_get_window(widget)); | |
| 199 if (is_drawing_attention_) | |
| 200 paint_state_ = PAINT_FOR_ATTENTION; | |
| 201 else if (window_height <= panel::kMinimizedPanelHeight) | |
| 202 paint_state_ = PAINT_AS_MINIMIZED; | |
| 203 else if (IsActive()) | |
| 204 paint_state_ = PAINT_AS_ACTIVE; | |
| 205 else | |
| 206 paint_state_ = PAINT_AS_INACTIVE; | |
| 207 | |
| 208 // Draw the background. | |
| 209 gfx::CairoCachedSurface* surface = GetFrameBackground()->ToCairo(); | |
| 210 surface->SetSource(cr, widget, 0, 0); | |
| 211 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); | |
| 212 cairo_rectangle(cr, event->area.x, event->area.y, | |
| 213 event->area.width, event->area.height); | |
| 214 cairo_fill(cr); | |
| 215 | |
| 216 // Draw the divider only if we're showing more than titlebar. | |
| 217 if (window_height > panel::kTitlebarHeight) { | |
| 218 cairo_set_source_rgb(cr, | |
| 219 SkColorGetR(kDividerColor) / 255.0, | |
| 220 SkColorGetG(kDividerColor) / 255.0, | |
| 221 SkColorGetB(kDividerColor) / 255.0); | |
| 222 cairo_rectangle(cr, 0, panel::kTitlebarHeight - 1, bounds_.width(), 1); | |
| 223 cairo_fill(cr); | |
| 224 } | |
| 225 | |
| 226 // Draw the border for the minimized panel only. | |
| 227 if (paint_state_ == PAINT_AS_MINIMIZED) { | |
| 228 cairo_move_to(cr, 0, 3); | |
| 229 cairo_line_to(cr, 1, 2); | |
| 230 cairo_line_to(cr, 1, 1); | |
| 231 cairo_line_to(cr, 2, 1); | |
| 232 cairo_line_to(cr, 3, 0); | |
| 233 cairo_line_to(cr, event->area.width - 3, 0); | |
| 234 cairo_line_to(cr, event->area.width - 2, 1); | |
| 235 cairo_line_to(cr, event->area.width - 1, 1); | |
| 236 cairo_line_to(cr, event->area.width - 1, 2); | |
| 237 cairo_line_to(cr, event->area.width - 1, 3); | |
| 238 cairo_line_to(cr, event->area.width - 1, event->area.height - 1); | |
| 239 cairo_line_to(cr, 0, event->area.height - 1); | |
| 240 cairo_close_path(cr); | |
| 241 cairo_set_source_rgb(cr, | |
| 242 SkColorGetR(kMinimizeBorderDefaultColor) / 255.0, | |
| 243 SkColorGetG(kMinimizeBorderDefaultColor) / 255.0, | |
| 244 SkColorGetB(kMinimizeBorderDefaultColor) / 255.0); | |
| 245 cairo_set_line_width(cr, 1.0); | |
| 246 cairo_stroke(cr); | |
| 247 } | |
| 248 | |
| 249 cairo_destroy(cr); | |
| 250 } | |
| 251 | |
| 252 void PanelBrowserWindowGtk::EnsureDragHelperCreated() { | |
| 253 if (drag_helper_.get()) | |
| 254 return; | |
| 255 | |
| 256 drag_helper_.reset(new PanelDragGtk(panel_.get())); | |
| 257 gtk_box_pack_end(GTK_BOX(window_vbox_), drag_helper_->widget(), | |
| 258 FALSE, FALSE, 0); | |
| 259 } | |
| 260 | |
| 261 bool PanelBrowserWindowGtk::HandleTitleBarLeftMousePress( | |
| 262 GdkEventButton* event) { | |
| 263 DCHECK_EQ(1U, event->button); | |
| 264 DCHECK_EQ(GDK_BUTTON_PRESS, event->type); | |
| 265 | |
| 266 EnsureDragHelperCreated(); | |
| 267 drag_helper_->InitialTitlebarMousePress(event, titlebar_widget()); | |
| 268 return TRUE; | |
| 269 } | |
| 270 | |
| 271 bool PanelBrowserWindowGtk::HandleWindowEdgeLeftMousePress( | |
| 272 GtkWindow* window, | |
| 273 GdkWindowEdge edge, | |
| 274 GdkEventButton* event) { | |
| 275 DCHECK_EQ(1U, event->button); | |
| 276 DCHECK_EQ(GDK_BUTTON_PRESS, event->type); | |
| 277 | |
| 278 EnsureDragHelperCreated(); | |
| 279 // Resize cursor was set by BrowserWindowGtk when mouse moved over | |
| 280 // window edge. | |
| 281 GdkCursor* cursor = | |
| 282 gdk_window_get_cursor(gtk_widget_get_window(GTK_WIDGET(window_))); | |
| 283 drag_helper_->InitialWindowEdgeMousePress(event, cursor, edge); | |
| 284 return TRUE; | |
| 285 } | |
| 286 | |
| 287 void PanelBrowserWindowGtk::SaveWindowPosition() { | |
| 288 // We don't save window position for panels as it's controlled by | |
| 289 // PanelManager. | |
| 290 return; | |
| 291 } | |
| 292 | |
| 293 void PanelBrowserWindowGtk::SetGeometryHints() { | |
| 294 // Set minimum height the window can be set to. | |
| 295 GdkGeometry hints; | |
| 296 hints.min_height = panel::kMinimizedPanelHeight; | |
| 297 hints.min_width = kMinWindowWidth; | |
| 298 gtk_window_set_geometry_hints( | |
| 299 window(), GTK_WIDGET(window()), &hints, GDK_HINT_MIN_SIZE); | |
| 300 | |
| 301 DCHECK(frame_size_.IsEmpty()); | |
| 302 } | |
| 303 | |
| 304 void PanelBrowserWindowGtk::SetBounds(const gfx::Rect& bounds) { | |
| 305 // This should never be called. | |
| 306 DLOG(WARNING) << "Unexpected call to PanelBrowserWindowGtk::SetBounds()"; | |
| 307 } | |
| 308 | |
| 309 void PanelBrowserWindowGtk::OnSizeChanged(int width, int height) { | |
| 310 BrowserWindowGtk::OnSizeChanged(width, height); | |
| 311 | |
| 312 if (!frame_size_.IsEmpty()) | |
| 313 return; | |
| 314 | |
| 315 // The system is allowed to size the window before the desired panel | |
| 316 // bounds are applied. Save the frame size allocated by the system as | |
| 317 // it will be affected when we shrink the panel smaller than the frame. | |
| 318 frame_size_ = GetNonClientFrameSize(); | |
| 319 | |
| 320 SetBoundsInternal(bounds_); | |
| 321 | |
| 322 panel_->OnWindowSizeAvailable(); | |
| 323 content::NotificationService::current()->Notify( | |
| 324 chrome::NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN, | |
| 325 content::Source<Panel>(panel_.get()), | |
| 326 content::NotificationService::NoDetails()); | |
| 327 } | |
| 328 | |
| 329 const gfx::Image* PanelBrowserWindowGtk::GetFrameBackground() const { | |
| 330 return UsingDefaultTheme() ? | |
| 331 GetDefaultFrameBackground() : GetThemedFrameBackground(); | |
| 332 } | |
| 333 | |
| 334 const gfx::Image* PanelBrowserWindowGtk::GetDefaultFrameBackground() const { | |
| 335 switch (paint_state_) { | |
| 336 case PAINT_AS_INACTIVE: | |
| 337 return GetInactiveBackgroundDefaultImage(); | |
| 338 case PAINT_AS_ACTIVE: | |
| 339 return GetActiveBackgroundDefaultImage(); | |
| 340 case PAINT_AS_MINIMIZED: | |
| 341 return GetMinimizeBackgroundDefaultImage(); | |
| 342 case PAINT_FOR_ATTENTION: | |
| 343 return GetAttentionBackgroundDefaultImage(); | |
| 344 default: | |
| 345 NOTREACHED(); | |
| 346 return GetInactiveBackgroundDefaultImage(); | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 const gfx::Image* PanelBrowserWindowGtk::GetThemedFrameBackground() const { | |
| 351 GtkThemeService* theme_provider = GtkThemeService::GetFrom(panel_->profile()); | |
| 352 return theme_provider->GetImageNamed(paint_state_ == PAINT_AS_ACTIVE ? | |
| 353 IDR_THEME_TOOLBAR : IDR_THEME_TAB_BACKGROUND); | |
| 354 } | |
| 355 | |
| 356 void PanelBrowserWindowGtk::ActiveWindowChanged(GdkWindow* active_window) { | |
| 357 bool was_active = IsActive(); | |
| 358 BrowserWindowGtk::ActiveWindowChanged(active_window); | |
| 359 bool is_active = IsActive(); | |
| 360 if (!window() || was_active == is_active) // State didn't change. | |
| 361 return; | |
| 362 | |
| 363 GetPanelTitlebar()->UpdateTextColor(); | |
| 364 panel_->OnActiveStateChanged(is_active); | |
| 365 } | |
| 366 | |
| 367 void PanelBrowserWindowGtk::Observe( | |
| 368 int type, | |
| 369 const content::NotificationSource& source, | |
| 370 const content::NotificationDetails& details) { | |
| 371 switch (type) { | |
| 372 case chrome::NOTIFICATION_WINDOW_CLOSED: | |
| 373 // Cleanup. | |
| 374 if (drag_helper_.get()) | |
| 375 drag_helper_.reset(); | |
| 376 | |
| 377 panel_->OnNativePanelClosed(); | |
| 378 break; | |
| 379 } | |
| 380 | |
| 381 BrowserWindowGtk::Observe(type, source, details); | |
| 382 } | |
| 383 | |
| 384 void PanelBrowserWindowGtk::ShowPanel() { | |
| 385 Show(); | |
| 386 } | |
| 387 | |
| 388 void PanelBrowserWindowGtk::ShowPanelInactive() { | |
| 389 ShowInactive(); | |
| 390 } | |
| 391 | |
| 392 gfx::Rect PanelBrowserWindowGtk::GetPanelBounds() const { | |
| 393 return bounds_; | |
| 394 } | |
| 395 | |
| 396 void PanelBrowserWindowGtk::SetPanelBounds(const gfx::Rect& bounds) { | |
| 397 SetBoundsInternal(bounds); | |
| 398 } | |
| 399 | |
| 400 void PanelBrowserWindowGtk::SetPanelBoundsInstantly(const gfx::Rect& bounds) { | |
| 401 SetBoundsInternal(bounds); | |
| 402 } | |
| 403 | |
| 404 void PanelBrowserWindowGtk::SetBoundsInternal(const gfx::Rect& bounds) { | |
| 405 gdk_window_move_resize(gtk_widget_get_window(GTK_WIDGET(window())), | |
| 406 bounds.x(), bounds.y(), | |
| 407 bounds.width(), bounds.height()); | |
| 408 | |
| 409 bounds_ = bounds; | |
| 410 | |
| 411 GetPanelTitlebar()->SendEnterNotifyToCloseButtonIfUnderMouse(); | |
| 412 panel_->manager()->OnPanelAnimationEnded(panel_.get()); | |
| 413 } | |
| 414 | |
| 415 void PanelBrowserWindowGtk::ClosePanel() { | |
| 416 Close(); | |
| 417 } | |
| 418 | |
| 419 void PanelBrowserWindowGtk::ActivatePanel() { | |
| 420 Activate(); | |
| 421 } | |
| 422 | |
| 423 void PanelBrowserWindowGtk::DeactivatePanel() { | |
| 424 BrowserWindow* browser_window = | |
| 425 panel_->manager()->GetNextBrowserWindowToActivate(GetPanelBrowser()); | |
| 426 if (browser_window) { | |
| 427 browser_window->Activate(); | |
| 428 } else { | |
| 429 Deactivate(); | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 bool PanelBrowserWindowGtk::IsPanelActive() const { | |
| 434 return IsActive(); | |
| 435 } | |
| 436 | |
| 437 void PanelBrowserWindowGtk::PreventActivationByOS(bool prevent_activation) { | |
| 438 gtk_window_set_accept_focus(window(), !prevent_activation); | |
| 439 return; | |
| 440 } | |
| 441 | |
| 442 gfx::NativeWindow PanelBrowserWindowGtk::GetNativePanelHandle() { | |
| 443 return GetNativeWindow(); | |
| 444 } | |
| 445 | |
| 446 void PanelBrowserWindowGtk::UpdatePanelTitleBar() { | |
| 447 UpdateTitleBar(); | |
| 448 } | |
| 449 | |
| 450 void PanelBrowserWindowGtk::UpdatePanelLoadingAnimations(bool should_animate) { | |
| 451 UpdateLoadingAnimations(should_animate); | |
| 452 } | |
| 453 | |
| 454 void PanelBrowserWindowGtk::ShowTaskManagerForPanel() { | |
| 455 ShowTaskManager(); | |
| 456 } | |
| 457 | |
| 458 FindBar* PanelBrowserWindowGtk::CreatePanelFindBar() { | |
| 459 return CreateFindBar(); | |
| 460 } | |
| 461 | |
| 462 void PanelBrowserWindowGtk::NotifyPanelOnUserChangedTheme() { | |
| 463 UserChangedTheme(); | |
| 464 } | |
| 465 | |
| 466 void PanelBrowserWindowGtk::PanelWebContentsFocused(WebContents* contents) { | |
| 467 WebContentsFocused(contents); | |
| 468 } | |
| 469 | |
| 470 void PanelBrowserWindowGtk::PanelCut() { | |
| 471 Cut(); | |
| 472 } | |
| 473 | |
| 474 void PanelBrowserWindowGtk::PanelCopy() { | |
| 475 Copy(); | |
| 476 } | |
| 477 | |
| 478 void PanelBrowserWindowGtk::PanelPaste() { | |
| 479 Paste(); | |
| 480 } | |
| 481 | |
| 482 void PanelBrowserWindowGtk::DrawAttention(bool draw_attention) { | |
| 483 DCHECK((panel_->attention_mode() & Panel::USE_PANEL_ATTENTION) != 0); | |
| 484 | |
| 485 if (is_drawing_attention_ == draw_attention) | |
| 486 return; | |
| 487 | |
| 488 is_drawing_attention_ = draw_attention; | |
| 489 | |
| 490 GetPanelTitlebar()->UpdateTextColor(); | |
| 491 InvalidateWindow(); | |
| 492 | |
| 493 if ((panel_->attention_mode() & Panel::USE_SYSTEM_ATTENTION) != 0) | |
| 494 ::BrowserWindowGtk::FlashFrame(draw_attention); | |
| 495 } | |
| 496 | |
| 497 bool PanelBrowserWindowGtk::IsDrawingAttention() const { | |
| 498 return is_drawing_attention_; | |
| 499 } | |
| 500 | |
| 501 bool PanelBrowserWindowGtk::PreHandlePanelKeyboardEvent( | |
| 502 const NativeWebKeyboardEvent& event, | |
| 503 bool* is_keyboard_shortcut) { | |
| 504 return PreHandleKeyboardEvent(event, is_keyboard_shortcut); | |
| 505 } | |
| 506 | |
| 507 void PanelBrowserWindowGtk::FullScreenModeChanged(bool is_full_screen) { | |
| 508 // Nothing to do here as z-order rules for panels ensures that they're below | |
| 509 // any app running in full screen mode. | |
| 510 } | |
| 511 | |
| 512 void PanelBrowserWindowGtk::HandlePanelKeyboardEvent( | |
| 513 const NativeWebKeyboardEvent& event) { | |
| 514 HandleKeyboardEvent(event); | |
| 515 } | |
| 516 | |
| 517 Browser* PanelBrowserWindowGtk::GetPanelBrowser() const { | |
| 518 return browser(); | |
| 519 } | |
| 520 | |
| 521 void PanelBrowserWindowGtk::DestroyPanelBrowser() { | |
| 522 DestroyBrowser(); | |
| 523 } | |
| 524 | |
| 525 void PanelBrowserWindowGtk::EnsurePanelFullyVisible() { | |
| 526 gtk_window_present(window()); | |
| 527 } | |
| 528 | |
| 529 void PanelBrowserWindowGtk::SetPanelAlwaysOnTop(bool on_top) { | |
| 530 gtk_window_set_keep_above(window(), on_top); | |
| 531 } | |
| 532 | |
| 533 void PanelBrowserWindowGtk::EnableResizeByMouse(bool enable) { | |
| 534 } | |
| 535 | |
| 536 void PanelBrowserWindowGtk::UpdatePanelMinimizeRestoreButtonVisibility() { | |
| 537 GetPanelTitlebar()->UpdateMinimizeRestoreButtonVisibility(); | |
| 538 } | |
| 539 | |
| 540 gfx::Size PanelBrowserWindowGtk::WindowSizeFromContentSize( | |
| 541 const gfx::Size& content_size) const { | |
| 542 return gfx::Size(content_size.width() + frame_size_.width(), | |
| 543 content_size.height() + frame_size_.height()); | |
| 544 } | |
| 545 | |
| 546 gfx::Size PanelBrowserWindowGtk::ContentSizeFromWindowSize( | |
| 547 const gfx::Size& window_size) const { | |
| 548 return gfx::Size(window_size.width() - frame_size_.width(), | |
| 549 window_size.height() - frame_size_.height()); | |
| 550 } | |
| 551 | |
| 552 int PanelBrowserWindowGtk::TitleOnlyHeight() const { | |
| 553 GtkAllocation allocation; | |
| 554 gtk_widget_get_allocation(titlebar_widget(), &allocation); | |
| 555 return allocation.height; | |
| 556 } | |
| 557 | |
| 558 gboolean PanelBrowserWindowGtk::OnTitlebarButtonReleaseEvent( | |
| 559 GtkWidget* widget, GdkEventButton* event) { | |
| 560 if (event->button != 1) | |
| 561 return TRUE; | |
| 562 | |
| 563 panel_->OnTitlebarClicked((event->state & GDK_CONTROL_MASK) ? | |
| 564 panel::APPLY_TO_ALL : panel::NO_MODIFIER); | |
| 565 return TRUE; | |
| 566 } | |
| 567 | |
| 568 void PanelBrowserWindowGtk::PanelExpansionStateChanging( | |
| 569 Panel::ExpansionState old_state, Panel::ExpansionState new_state) { | |
| 570 } | |
| 571 | |
| 572 // NativePanelTesting implementation. | |
| 573 class NativePanelTestingGtk : public NativePanelTesting { | |
| 574 public: | |
| 575 explicit NativePanelTestingGtk( | |
| 576 PanelBrowserWindowGtk* panel_browser_window_gtk); | |
| 577 | |
| 578 private: | |
| 579 virtual void PressLeftMouseButtonTitlebar( | |
| 580 const gfx::Point& mouse_location, panel::ClickModifier modifier) OVERRIDE; | |
| 581 virtual void ReleaseMouseButtonTitlebar( | |
| 582 panel::ClickModifier modifier) OVERRIDE; | |
| 583 virtual void DragTitlebar(const gfx::Point& mouse_location) OVERRIDE; | |
| 584 virtual void CancelDragTitlebar() OVERRIDE; | |
| 585 virtual void FinishDragTitlebar() OVERRIDE; | |
| 586 virtual bool VerifyDrawingAttention() const OVERRIDE; | |
| 587 virtual bool VerifyActiveState(bool is_active) OVERRIDE; | |
| 588 virtual void WaitForWindowCreationToComplete() const OVERRIDE; | |
| 589 virtual bool IsWindowSizeKnown() const OVERRIDE; | |
| 590 virtual bool IsAnimatingBounds() const OVERRIDE; | |
| 591 virtual bool IsButtonVisible( | |
| 592 panel::TitlebarButtonType button_type) const OVERRIDE; | |
| 593 | |
| 594 PanelBrowserWindowGtk* panel_browser_window_gtk_; | |
| 595 }; | |
| 596 | |
| 597 NativePanelTesting* PanelBrowserWindowGtk::CreateNativePanelTesting() { | |
| 598 return new NativePanelTestingGtk(this); | |
| 599 } | |
| 600 | |
| 601 NativePanelTestingGtk::NativePanelTestingGtk( | |
| 602 PanelBrowserWindowGtk* panel_browser_window_gtk) : | |
| 603 panel_browser_window_gtk_(panel_browser_window_gtk) { | |
| 604 } | |
| 605 | |
| 606 void NativePanelTestingGtk::PressLeftMouseButtonTitlebar( | |
| 607 const gfx::Point& mouse_location, panel::ClickModifier modifier) { | |
| 608 | |
| 609 GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS); | |
| 610 event->button.button = 1; | |
| 611 event->button.x_root = mouse_location.x(); | |
| 612 event->button.y_root = mouse_location.y(); | |
| 613 if (modifier == panel::APPLY_TO_ALL) | |
| 614 event->button.state |= GDK_CONTROL_MASK; | |
| 615 panel_browser_window_gtk_->HandleTitleBarLeftMousePress( | |
| 616 reinterpret_cast<GdkEventButton*>(event)); | |
| 617 gdk_event_free(event); | |
| 618 MessageLoopForUI::current()->RunAllPending(); | |
| 619 } | |
| 620 | |
| 621 void NativePanelTestingGtk::ReleaseMouseButtonTitlebar( | |
| 622 panel::ClickModifier modifier) { | |
| 623 GdkEvent* event = gdk_event_new(GDK_BUTTON_RELEASE); | |
| 624 event->button.button = 1; | |
| 625 if (modifier == panel::APPLY_TO_ALL) | |
| 626 event->button.state |= GDK_CONTROL_MASK; | |
| 627 if (panel_browser_window_gtk_->drag_helper_.get()) { | |
| 628 panel_browser_window_gtk_->drag_helper_->OnButtonReleaseEvent( | |
| 629 NULL, reinterpret_cast<GdkEventButton*>(event)); | |
| 630 } else { | |
| 631 panel_browser_window_gtk_->OnTitlebarButtonReleaseEvent( | |
| 632 NULL, reinterpret_cast<GdkEventButton*>(event)); | |
| 633 } | |
| 634 gdk_event_free(event); | |
| 635 MessageLoopForUI::current()->RunAllPending(); | |
| 636 } | |
| 637 | |
| 638 void NativePanelTestingGtk::DragTitlebar(const gfx::Point& mouse_location) { | |
| 639 if (!panel_browser_window_gtk_->drag_helper_.get()) | |
| 640 return; | |
| 641 GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY); | |
| 642 event->motion.x_root = mouse_location.x(); | |
| 643 event->motion.y_root = mouse_location.y(); | |
| 644 panel_browser_window_gtk_->drag_helper_->OnMouseMoveEvent( | |
| 645 NULL, reinterpret_cast<GdkEventMotion*>(event)); | |
| 646 gdk_event_free(event); | |
| 647 MessageLoopForUI::current()->RunAllPending(); | |
| 648 } | |
| 649 | |
| 650 void NativePanelTestingGtk::CancelDragTitlebar() { | |
| 651 if (!panel_browser_window_gtk_->drag_helper_.get()) | |
| 652 return; | |
| 653 panel_browser_window_gtk_->drag_helper_->OnGrabBrokenEvent(NULL, NULL); | |
| 654 MessageLoopForUI::current()->RunAllPending(); | |
| 655 } | |
| 656 | |
| 657 void NativePanelTestingGtk::FinishDragTitlebar() { | |
| 658 if (!panel_browser_window_gtk_->drag_helper_.get()) | |
| 659 return; | |
| 660 ReleaseMouseButtonTitlebar(panel::NO_MODIFIER); | |
| 661 } | |
| 662 | |
| 663 bool NativePanelTestingGtk::VerifyDrawingAttention() const { | |
| 664 return panel_browser_window_gtk_->IsDrawingAttention(); | |
| 665 } | |
| 666 | |
| 667 bool NativePanelTestingGtk::VerifyActiveState(bool is_active) { | |
| 668 // TODO(jianli): to be implemented. http://crbug.com/102737 | |
| 669 return false; | |
| 670 } | |
| 671 | |
| 672 void NativePanelTestingGtk::WaitForWindowCreationToComplete() const { | |
| 673 while (panel_browser_window_gtk_->frame_size_.IsEmpty()) | |
| 674 MessageLoopForUI::current()->RunAllPending(); | |
| 675 } | |
| 676 | |
| 677 bool NativePanelTestingGtk::IsWindowSizeKnown() const { | |
| 678 return !panel_browser_window_gtk_->frame_size_.IsEmpty(); | |
| 679 } | |
| 680 | |
| 681 bool NativePanelTestingGtk::IsAnimatingBounds() const { | |
| 682 return false; | |
| 683 } | |
| 684 | |
| 685 bool NativePanelTestingGtk::IsButtonVisible( | |
| 686 panel::TitlebarButtonType button_type) const { | |
| 687 PanelBrowserTitlebarGtk* titlebar = | |
| 688 panel_browser_window_gtk_->GetPanelTitlebar(); | |
| 689 CustomDrawButton* button; | |
| 690 switch (button_type) { | |
| 691 case panel::CLOSE_BUTTON: | |
| 692 button = titlebar->close_button(); | |
| 693 break; | |
| 694 case panel::MINIMIZE_BUTTON: | |
| 695 button = titlebar->minimize_button(); | |
| 696 break; | |
| 697 case panel::RESTORE_BUTTON: | |
| 698 button = titlebar->restore_button(); | |
| 699 break; | |
| 700 default: | |
| 701 NOTREACHED(); | |
| 702 return false; | |
| 703 } | |
| 704 return gtk_widget_get_visible(button->widget()); | |
| 705 } | |
| OLD | NEW |