Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(689)

Side by Side Diff: chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.cc

Issue 23257002: gtk: Fix use after free (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 0U Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698