| Index: chrome/browser/gtk/info_bubble_gtk.cc
|
| ===================================================================
|
| --- chrome/browser/gtk/info_bubble_gtk.cc (revision 42274)
|
| +++ chrome/browser/gtk/info_bubble_gtk.cc (working copy)
|
| @@ -49,10 +49,11 @@
|
| GtkWidget* content,
|
| ArrowLocationGtk arrow_location,
|
| bool match_system_theme,
|
| + bool grab_input,
|
| GtkThemeProvider* provider,
|
| InfoBubbleGtkDelegate* delegate) {
|
| InfoBubbleGtk* bubble = new InfoBubbleGtk(provider, match_system_theme);
|
| - bubble->Init(toplevel_window, rect, content, arrow_location);
|
| + bubble->Init(toplevel_window, rect, content, arrow_location, grab_input);
|
| bubble->set_delegate(delegate);
|
| return bubble;
|
| }
|
| @@ -67,37 +68,51 @@
|
| mask_region_(NULL),
|
| preferred_arrow_location_(ARROW_LOCATION_TOP_LEFT),
|
| current_arrow_location_(ARROW_LOCATION_TOP_LEFT),
|
| - match_system_theme_(match_system_theme) {
|
| + match_system_theme_(match_system_theme),
|
| + grab_input_(true),
|
| + closed_by_escape_(false) {
|
| }
|
|
|
| InfoBubbleGtk::~InfoBubbleGtk() {
|
| + // Notify the delegate that we're about to close. This gives the chance
|
| + // to save state / etc from the hosted widget before it's destroyed.
|
| + if (delegate_)
|
| + delegate_->InfoBubbleClosing(this, closed_by_escape_);
|
| +
|
| g_object_unref(accel_group_);
|
| if (mask_region_) {
|
| gdk_region_destroy(mask_region_);
|
| mask_region_ = NULL;
|
| }
|
|
|
| - g_signal_handlers_disconnect_by_func(
|
| - toplevel_window_,
|
| - reinterpret_cast<gpointer>(HandleToplevelConfigureThunk),
|
| - this);
|
| - g_signal_handlers_disconnect_by_func(
|
| - toplevel_window_,
|
| - reinterpret_cast<gpointer>(HandleToplevelUnmapThunk),
|
| - this);
|
| + if (toplevel_window_) {
|
| + g_signal_handlers_disconnect_by_func(
|
| + toplevel_window_,
|
| + reinterpret_cast<gpointer>(HandleToplevelConfigureThunk),
|
| + this);
|
| + g_signal_handlers_disconnect_by_func(
|
| + toplevel_window_,
|
| + reinterpret_cast<gpointer>(HandleToplevelUnmapThunk),
|
| + this);
|
| + }
|
| toplevel_window_ = NULL;
|
| }
|
|
|
| void InfoBubbleGtk::Init(GtkWindow* toplevel_window,
|
| const gfx::Rect& rect,
|
| GtkWidget* content,
|
| - ArrowLocationGtk arrow_location) {
|
| + ArrowLocationGtk arrow_location,
|
| + bool grab_input) {
|
| DCHECK(!window_);
|
| toplevel_window_ = toplevel_window;
|
| rect_ = rect;
|
| preferred_arrow_location_ = arrow_location;
|
|
|
| - window_ = gtk_window_new(GTK_WINDOW_POPUP);
|
| + grab_input_ = grab_input;
|
| + // Using a TOPLEVEL window may cause placement issues with certain WMs but it
|
| + // is necessary to be able to focus the window.
|
| + window_ = gtk_window_new(grab_input ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
|
| +
|
| gtk_widget_set_app_paintable(window_, TRUE);
|
| // Resizing is handled by the program, not user.
|
| gtk_window_set_resizable(GTK_WINDOW(window_), FALSE);
|
| @@ -140,26 +155,31 @@
|
| G_CALLBACK(&HandleToplevelConfigureThunk), this);
|
| g_signal_connect(toplevel_window, "unmap-event",
|
| G_CALLBACK(&HandleToplevelUnmapThunk), this);
|
| + // Set |toplevel_window_| to NULL if it gets destroyed.
|
| + g_signal_connect(toplevel_window, "destroy",
|
| + G_CALLBACK(gtk_widget_destroyed), &toplevel_window_);
|
|
|
| gtk_widget_show_all(window_);
|
|
|
| - // We add a GTK (application-level) grab. This means we will get all
|
| - // mouse events for our application, even if they were delivered on another
|
| - // window. We don't need this to get button presses outside of the bubble's
|
| - // window so we'll know to close it (the pointer grab takes care of that), but
|
| - // it prevents other widgets from getting highlighted when the pointer moves
|
| - // over them.
|
| - //
|
| - // (Ideally we wouldn't add the window to a group and it would just get all
|
| - // the mouse events, but gtk_grab_add() doesn't appear to do anything in that
|
| - // case. Adding it to the toplevel window's group first appears to block
|
| - // enter/leave events for that window and its subwindows, although other
|
| - // browser windows still receive them).
|
| - gtk_window_group_add_window(gtk_window_get_group(toplevel_window),
|
| - GTK_WINDOW(window_));
|
| - gtk_grab_add(window_);
|
| + if (grab_input_) {
|
| + // We add a GTK (application-level) grab. This means we will get all
|
| + // mouse events for our application, even if they were delivered on another
|
| + // window. We don't need this to get button presses outside of the bubble's
|
| + // window so we'll know to close it (the pointer grab takes care of that),
|
| + // but it prevents other widgets from getting highlighted when the pointer
|
| + // moves over them.
|
| + //
|
| + // (Ideally we wouldn't add the window to a group and it would just get all
|
| + // the mouse events, but gtk_grab_add() doesn't appear to do anything in
|
| + // that case. Adding it to the toplevel window's group first appears to
|
| + // block enter/leave events for that window and its subwindows, although
|
| + // other browser windows still receive them).
|
| + gtk_window_group_add_window(gtk_window_get_group(toplevel_window),
|
| + GTK_WINDOW(window_));
|
| + gtk_grab_add(window_);
|
|
|
| - GrabPointerAndKeyboard();
|
| + GrabPointerAndKeyboard();
|
| + }
|
|
|
| registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
|
| NotificationService::AllSources());
|
| @@ -321,18 +341,13 @@
|
| }
|
|
|
| void InfoBubbleGtk::HandlePointerAndKeyboardUngrabbedByContent() {
|
| - GrabPointerAndKeyboard();
|
| + if (grab_input_)
|
| + GrabPointerAndKeyboard();
|
| }
|
|
|
| -void InfoBubbleGtk::CloseInternal(bool closed_by_escape) {
|
| - // Notify the delegate that we're about to close. This gives the chance
|
| - // to save state / etc from the hosted widget before it's destroyed.
|
| - if (delegate_)
|
| - delegate_->InfoBubbleClosing(this, closed_by_escape);
|
| -
|
| +void InfoBubbleGtk::Close() {
|
| // We don't need to ungrab the pointer or keyboard here; the X server will
|
| // automatically do that when we destroy our window.
|
| -
|
| DCHECK(window_);
|
| gtk_widget_destroy(window_);
|
| // |this| has been deleted, see HandleDestroy.
|
| @@ -365,7 +380,8 @@
|
| }
|
|
|
| gboolean InfoBubbleGtk::HandleEscape() {
|
| - CloseInternal(true); // Close by escape.
|
| + closed_by_escape_ = true;
|
| + Close();
|
| return TRUE;
|
| }
|
|
|
| @@ -411,9 +427,13 @@
|
| return FALSE;
|
| }
|
|
|
| - // Otherwise we had a click outside of our window, close ourself.
|
| - Close();
|
| - return TRUE;
|
| + if (grab_input_) {
|
| + // Otherwise we had a click outside of our window, close ourself.
|
| + Close();
|
| + return TRUE;
|
| + }
|
| +
|
| + return FALSE;
|
| }
|
|
|
| gboolean InfoBubbleGtk::HandleDestroy() {
|
|
|