| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h" | 5 #include "chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h" |
| 6 | 6 |
| 7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include "chrome/browser/ui/gtk/gtk_theme_service.h" | 24 #include "chrome/browser/ui/gtk/gtk_theme_service.h" |
| 25 #include "chrome/browser/ui/gtk/gtk_util.h" | 25 #include "chrome/browser/ui/gtk/gtk_util.h" |
| 26 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" | 26 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" |
| 27 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" | 27 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" |
| 28 #include "chrome/browser/ui/omnibox/omnibox_view.h" | 28 #include "chrome/browser/ui/omnibox/omnibox_view.h" |
| 29 #include "content/public/browser/notification_source.h" | 29 #include "content/public/browser/notification_source.h" |
| 30 #include "grit/theme_resources.h" | 30 #include "grit/theme_resources.h" |
| 31 #include "ui/base/gtk/gtk_compat.h" | 31 #include "ui/base/gtk/gtk_compat.h" |
| 32 #include "ui/base/gtk/gtk_hig_constants.h" | 32 #include "ui/base/gtk/gtk_hig_constants.h" |
| 33 #include "ui/base/gtk/gtk_screen_util.h" | 33 #include "ui/base/gtk/gtk_screen_util.h" |
| 34 #include "ui/base/gtk/gtk_signal_registrar.h" | |
| 35 #include "ui/base/gtk/gtk_windowing.h" | 34 #include "ui/base/gtk/gtk_windowing.h" |
| 36 #include "ui/gfx/color_utils.h" | 35 #include "ui/gfx/color_utils.h" |
| 37 #include "ui/gfx/font.h" | 36 #include "ui/gfx/font.h" |
| 38 #include "ui/gfx/gtk_util.h" | 37 #include "ui/gfx/gtk_util.h" |
| 39 #include "ui/gfx/image/cairo_cached_surface.h" | 38 #include "ui/gfx/image/cairo_cached_surface.h" |
| 40 #include "ui/gfx/image/image.h" | 39 #include "ui/gfx/image/image.h" |
| 41 #include "ui/gfx/rect.h" | 40 #include "ui/gfx/rect.h" |
| 42 #include "ui/gfx/skia_utils_gtk.h" | 41 #include "ui/gfx/skia_utils_gtk.h" |
| 43 | 42 |
| 44 namespace { | 43 namespace { |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 | 259 |
| 261 pango_layout_set_text(layout, text_utf8.data(), text_utf8.length()); | 260 pango_layout_set_text(layout, text_utf8.data(), text_utf8.length()); |
| 262 pango_layout_set_attributes(layout, attrs); // Ref taken. | 261 pango_layout_set_attributes(layout, attrs); // Ref taken. |
| 263 pango_attr_list_unref(attrs); | 262 pango_attr_list_unref(attrs); |
| 264 } | 263 } |
| 265 | 264 |
| 266 OmniboxPopupViewGtk::OmniboxPopupViewGtk(const gfx::Font& font, | 265 OmniboxPopupViewGtk::OmniboxPopupViewGtk(const gfx::Font& font, |
| 267 OmniboxView* omnibox_view, | 266 OmniboxView* omnibox_view, |
| 268 OmniboxEditModel* edit_model, | 267 OmniboxEditModel* edit_model, |
| 269 GtkWidget* location_bar) | 268 GtkWidget* location_bar) |
| 270 : signal_registrar_(new ui::GtkSignalRegistrar), | 269 : model_(new OmniboxPopupModel(this, edit_model)), |
| 271 model_(new OmniboxPopupModel(this, edit_model)), | |
| 272 omnibox_view_(omnibox_view), | 270 omnibox_view_(omnibox_view), |
| 273 location_bar_(location_bar), | 271 location_bar_(location_bar), |
| 274 window_(gtk_window_new(GTK_WINDOW_POPUP)), | 272 window_(gtk_window_new(GTK_WINDOW_POPUP)), |
| 275 layout_(NULL), | 273 layout_(NULL), |
| 276 theme_service_(GtkThemeService::GetFrom(edit_model->profile())), | 274 theme_service_(GtkThemeService::GetFrom(edit_model->profile())), |
| 277 font_(font.DeriveFont(kEditFontAdjust)), | 275 font_(font.DeriveFont(kEditFontAdjust)), |
| 278 ignore_mouse_drag_(false), | 276 ignore_mouse_drag_(false), |
| 279 opened_(false) { | 277 opened_(false) { |
| 280 gtk_widget_set_can_focus(window_, FALSE); | 278 gtk_widget_set_can_focus(window_, FALSE); |
| 281 // Don't allow the window to be resized. This also forces the window to | 279 // Don't allow the window to be resized. This also forces the window to |
| 282 // shrink down to the size of its child contents. | 280 // shrink down to the size of its child contents. |
| 283 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); | 281 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); |
| 284 gtk_widget_set_app_paintable(window_, TRUE); | 282 gtk_widget_set_app_paintable(window_, TRUE); |
| 285 // Have GTK double buffer around the expose signal. | 283 // Have GTK double buffer around the expose signal. |
| 286 gtk_widget_set_double_buffered(window_, TRUE); | 284 gtk_widget_set_double_buffered(window_, TRUE); |
| 287 | 285 |
| 288 // Cache the layout so we don't have to create it for every expose. If we | 286 // Cache the layout so we don't have to create it for every expose. If we |
| 289 // were a real widget we should handle changing directions, but we're not | 287 // were a real widget we should handle changing directions, but we're not |
| 290 // doing RTL or anything yet, so it shouldn't be important now. | 288 // doing RTL or anything yet, so it shouldn't be important now. |
| 291 layout_ = gtk_widget_create_pango_layout(window_, NULL); | 289 layout_ = gtk_widget_create_pango_layout(window_, NULL); |
| 292 // We don't want the layout of search results depending on their language. | 290 // We don't want the layout of search results depending on their language. |
| 293 pango_layout_set_auto_dir(layout_, FALSE); | 291 pango_layout_set_auto_dir(layout_, FALSE); |
| 294 // We always ellipsize when drawing our text runs. | 292 // We always ellipsize when drawing our text runs. |
| 295 pango_layout_set_ellipsize(layout_, PANGO_ELLIPSIZE_END); | 293 pango_layout_set_ellipsize(layout_, PANGO_ELLIPSIZE_END); |
| 296 | 294 |
| 297 gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK | | 295 gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK | |
| 298 GDK_POINTER_MOTION_MASK | | 296 GDK_POINTER_MOTION_MASK | |
| 299 GDK_BUTTON_PRESS_MASK | | 297 GDK_BUTTON_PRESS_MASK | |
| 300 GDK_BUTTON_RELEASE_MASK); | 298 GDK_BUTTON_RELEASE_MASK); |
| 301 signal_registrar_->Connect(window_, "motion-notify-event", | 299 g_signal_connect(window_, "motion-notify-event", |
| 302 G_CALLBACK(HandleMotionThunk), this); | 300 G_CALLBACK(HandleMotionThunk), this); |
| 303 signal_registrar_->Connect(window_, "button-press-event", | 301 g_signal_connect(window_, "button-press-event", |
| 304 G_CALLBACK(HandleButtonPressThunk), this); | 302 G_CALLBACK(HandleButtonPressThunk), this); |
| 305 signal_registrar_->Connect(window_, "button-release-event", | 303 g_signal_connect(window_, "button-release-event", |
| 306 G_CALLBACK(HandleButtonReleaseThunk), this); | 304 G_CALLBACK(HandleButtonReleaseThunk), this); |
| 307 signal_registrar_->Connect(window_, "expose-event", | 305 g_signal_connect(window_, "expose-event", |
| 308 G_CALLBACK(HandleExposeThunk), this); | 306 G_CALLBACK(HandleExposeThunk), this); |
| 309 | 307 |
| 310 registrar_.Add(this, | 308 registrar_.Add(this, |
| 311 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, | 309 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
| 312 content::Source<ThemeService>(theme_service_)); | 310 content::Source<ThemeService>(theme_service_)); |
| 313 theme_service_->InitThemesFor(this); | 311 theme_service_->InitThemesFor(this); |
| 314 | 312 |
| 315 // TODO(erg): There appears to be a bug somewhere in something which shows | 313 // TODO(erg): There appears to be a bug somewhere in something which shows |
| 316 // itself when we're in NX. Previously, we called | 314 // itself when we're in NX. Previously, we called |
| 317 // gtk_util::ActAsRoundedWindow() to make this popup have rounded | 315 // gtk_util::ActAsRoundedWindow() to make this popup have rounded |
| 318 // corners. This worked on the standard xorg server (both locally and | 316 // corners. This worked on the standard xorg server (both locally and |
| 319 // remotely), but broke over NX. My current hypothesis is that it can't | 317 // remotely), but broke over NX. My current hypothesis is that it can't |
| 320 // handle shaping top-level windows during an expose event, but I'm not sure | 318 // handle shaping top-level windows during an expose event, but I'm not sure |
| 321 // how else to get accurate shaping information. | 319 // how else to get accurate shaping information. |
| 322 // | 320 // |
| 323 // r25080 (the original patch that added rounded corners here) should | 321 // r25080 (the original patch that added rounded corners here) should |
| 324 // eventually be cherry picked once I know what's going | 322 // eventually be cherry picked once I know what's going |
| 325 // on. http://crbug.com/22015. | 323 // on. http://crbug.com/22015. |
| 326 } | 324 } |
| 327 | 325 |
| 328 OmniboxPopupViewGtk::~OmniboxPopupViewGtk() { | 326 OmniboxPopupViewGtk::~OmniboxPopupViewGtk() { |
| 329 // Stop listening to our signals before we destroy the model. I suspect that | |
| 330 // we can race window destruction, otherwise. | |
| 331 signal_registrar_.reset(); | |
| 332 | |
| 333 // Explicitly destroy our model here, before we destroy our GTK widgets. | 327 // Explicitly destroy our model here, before we destroy our GTK widgets. |
| 334 // This is because the model destructor can call back into us, and we need | 328 // This is because the model destructor can call back into us, and we need |
| 335 // to make sure everything is still valid when it does. | 329 // to make sure everything is still valid when it does. |
| 336 model_.reset(); | 330 model_.reset(); |
| 337 g_object_unref(layout_); | 331 g_object_unref(layout_); |
| 338 gtk_widget_destroy(window_); | 332 gtk_widget_destroy(window_); |
| 339 } | 333 } |
| 340 | 334 |
| 341 bool OmniboxPopupViewGtk::IsOpen() const { | 335 bool OmniboxPopupViewGtk::IsOpen() const { |
| 342 return opened_; | 336 return opened_; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 | 454 |
| 461 void OmniboxPopupViewGtk::StackWindow() { | 455 void OmniboxPopupViewGtk::StackWindow() { |
| 462 gfx::NativeView omnibox_view = omnibox_view_->GetNativeView(); | 456 gfx::NativeView omnibox_view = omnibox_view_->GetNativeView(); |
| 463 DCHECK(GTK_IS_WIDGET(omnibox_view)); | 457 DCHECK(GTK_IS_WIDGET(omnibox_view)); |
| 464 GtkWidget* toplevel = gtk_widget_get_toplevel(omnibox_view); | 458 GtkWidget* toplevel = gtk_widget_get_toplevel(omnibox_view); |
| 465 DCHECK(gtk_widget_is_toplevel(toplevel)); | 459 DCHECK(gtk_widget_is_toplevel(toplevel)); |
| 466 ui::StackPopupWindow(window_, toplevel); | 460 ui::StackPopupWindow(window_, toplevel); |
| 467 } | 461 } |
| 468 | 462 |
| 469 size_t OmniboxPopupViewGtk::LineFromY(int y) { | 463 size_t OmniboxPopupViewGtk::LineFromY(int y) { |
| 464 DCHECK_NE(0U, model_->result().size()); |
| 470 size_t line = std::max(y - kBorderThickness, 0) / kHeightPerResult; | 465 size_t line = std::max(y - kBorderThickness, 0) / kHeightPerResult; |
| 471 return std::min(line, model_->result().size() - 1); | 466 return std::min(line, model_->result().size() - 1); |
| 472 } | 467 } |
| 473 | 468 |
| 474 void OmniboxPopupViewGtk::AcceptLine(size_t line, | 469 void OmniboxPopupViewGtk::AcceptLine(size_t line, |
| 475 WindowOpenDisposition disposition) { | 470 WindowOpenDisposition disposition) { |
| 476 // OpenMatch() may close the popup, which will clear the result set and, by | 471 // OpenMatch() may close the popup, which will clear the result set and, by |
| 477 // extension, |match| and its contents. So copy the relevant match out to | 472 // extension, |match| and its contents. So copy the relevant match out to |
| 478 // make sure it stays alive until the call completes. | 473 // make sure it stays alive until the call completes. |
| 479 AutocompleteMatch match = model_->result().match_at(line); | 474 AutocompleteMatch match = model_->result().match_at(line); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 *is_selected_keyword = true; | 530 *is_selected_keyword = true; |
| 536 return; | 531 return; |
| 537 } | 532 } |
| 538 | 533 |
| 539 *match = &result.match_at(index); | 534 *match = &result.match_at(index); |
| 540 *is_selected_keyword = false; | 535 *is_selected_keyword = false; |
| 541 } | 536 } |
| 542 | 537 |
| 543 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, | 538 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, |
| 544 GdkEventMotion* event) { | 539 GdkEventMotion* event) { |
| 540 if (!IsOpen()) |
| 541 return FALSE; |
| 542 |
| 545 // TODO(deanm): Windows has a bunch of complicated logic here. | 543 // TODO(deanm): Windows has a bunch of complicated logic here. |
| 546 size_t line = LineFromY(static_cast<int>(event->y)); | 544 size_t line = LineFromY(static_cast<int>(event->y)); |
| 547 // There is both a hovered and selected line, hovered just means your mouse | 545 // There is both a hovered and selected line, hovered just means your mouse |
| 548 // is over it, but selected is what's showing in the location edit. | 546 // is over it, but selected is what's showing in the location edit. |
| 549 model_->SetHoveredLine(line); | 547 model_->SetHoveredLine(line); |
| 550 // Select the line if the user has the left mouse button down. | 548 // Select the line if the user has the left mouse button down. |
| 551 if (!ignore_mouse_drag_ && (event->state & GDK_BUTTON1_MASK)) | 549 if (!ignore_mouse_drag_ && (event->state & GDK_BUTTON1_MASK)) |
| 552 model_->SetSelectedLine(line, false, false); | 550 model_->SetSelectedLine(line, false, false); |
| 553 return TRUE; | 551 return TRUE; |
| 554 } | 552 } |
| 555 | 553 |
| 556 gboolean OmniboxPopupViewGtk::HandleButtonPress(GtkWidget* widget, | 554 gboolean OmniboxPopupViewGtk::HandleButtonPress(GtkWidget* widget, |
| 557 GdkEventButton* event) { | 555 GdkEventButton* event) { |
| 556 if (!IsOpen()) |
| 557 return FALSE; |
| 558 |
| 558 ignore_mouse_drag_ = false; | 559 ignore_mouse_drag_ = false; |
| 559 // Very similar to HandleMotion. | 560 // Very similar to HandleMotion. |
| 560 size_t line = LineFromY(static_cast<int>(event->y)); | 561 size_t line = LineFromY(static_cast<int>(event->y)); |
| 561 model_->SetHoveredLine(line); | 562 model_->SetHoveredLine(line); |
| 562 if (event->button == 1) | 563 if (event->button == 1) |
| 563 model_->SetSelectedLine(line, false, false); | 564 model_->SetSelectedLine(line, false, false); |
| 564 return TRUE; | 565 return TRUE; |
| 565 } | 566 } |
| 566 | 567 |
| 567 gboolean OmniboxPopupViewGtk::HandleButtonRelease(GtkWidget* widget, | 568 gboolean OmniboxPopupViewGtk::HandleButtonRelease(GtkWidget* widget, |
| 568 GdkEventButton* event) { | 569 GdkEventButton* event) { |
| 570 if (!IsOpen()) |
| 571 return FALSE; |
| 572 |
| 569 if (ignore_mouse_drag_) { | 573 if (ignore_mouse_drag_) { |
| 570 // See header comment about this flag. | 574 // See header comment about this flag. |
| 571 ignore_mouse_drag_ = false; | 575 ignore_mouse_drag_ = false; |
| 572 return TRUE; | 576 return TRUE; |
| 573 } | 577 } |
| 574 | 578 |
| 575 size_t line = LineFromY(static_cast<int>(event->y)); | 579 size_t line = LineFromY(static_cast<int>(event->y)); |
| 576 switch (event->button) { | 580 switch (event->button) { |
| 577 case 1: // Left click. | 581 case 1: // Left click. |
| 578 AcceptLine(line, CURRENT_TAB); | 582 AcceptLine(line, CURRENT_TAB); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 theme_service_->GetImageNamed( | 725 theme_service_->GetImageNamed( |
| 722 is_selected ? IDR_OMNIBOX_TTS_DARK : | 726 is_selected ? IDR_OMNIBOX_TTS_DARK : |
| 723 IDR_OMNIBOX_TTS), | 727 IDR_OMNIBOX_TTS), |
| 724 icon_start_x, line_rect.y() + kIconTopPadding); | 728 icon_start_x, line_rect.y() + kIconTopPadding); |
| 725 } | 729 } |
| 726 } | 730 } |
| 727 | 731 |
| 728 cairo_destroy(cr); | 732 cairo_destroy(cr); |
| 729 return TRUE; | 733 return TRUE; |
| 730 } | 734 } |
| OLD | NEW |