OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/gtk/info_bubble_gtk.h" | 5 #include "chrome/browser/gtk/info_bubble_gtk.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/gfx/gtk_util.h" | 10 #include "base/gfx/gtk_util.h" |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 widget->allocation.width, widget->allocation.height, FRAME_STROKE); | 109 widget->allocation.width, widget->allocation.height, FRAME_STROKE); |
110 gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size()); | 110 gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size()); |
111 | 111 |
112 g_object_unref(gc); | 112 g_object_unref(gc); |
113 return FALSE; // Propagate so our children paint, etc. | 113 return FALSE; // Propagate so our children paint, etc. |
114 } | 114 } |
115 | 115 |
116 } // namespace | 116 } // namespace |
117 | 117 |
118 // static | 118 // static |
119 InfoBubbleGtk* InfoBubbleGtk::Show(const gfx::Rect& rect, GtkWidget* content) { | 119 InfoBubbleGtk* InfoBubbleGtk::Show(const gfx::Rect& rect, |
| 120 GtkWidget* content, |
| 121 InfoBubbleGtkDelegate* delegate) { |
120 InfoBubbleGtk* bubble = new InfoBubbleGtk(); | 122 InfoBubbleGtk* bubble = new InfoBubbleGtk(); |
121 bubble->Init(rect, content); | 123 bubble->Init(rect, content); |
| 124 bubble->set_delegate(delegate); |
122 return bubble; | 125 return bubble; |
123 } | 126 } |
124 | 127 |
125 InfoBubbleGtk::InfoBubbleGtk() | 128 InfoBubbleGtk::InfoBubbleGtk() |
126 : window_(NULL), | 129 : delegate_(NULL), |
| 130 window_(NULL), |
127 screen_x_(0), | 131 screen_x_(0), |
128 screen_y_(0), | 132 screen_y_(0) { |
129 closed_(false) { | 133 |
130 } | 134 } |
131 | 135 |
132 InfoBubbleGtk::~InfoBubbleGtk() { | 136 InfoBubbleGtk::~InfoBubbleGtk() { |
133 } | 137 } |
134 | 138 |
135 void InfoBubbleGtk::Init(const gfx::Rect& rect, GtkWidget* content) { | 139 void InfoBubbleGtk::Init(const gfx::Rect& rect, GtkWidget* content) { |
136 DCHECK(!window_); | 140 DCHECK(!window_); |
137 screen_x_ = rect.x() + (rect.width() / 2) - kArrowX; | 141 screen_x_ = rect.x() + (rect.width() / 2) - kArrowX; |
138 screen_y_ = rect.y() + rect.height() + kArrowToContentPadding; | 142 screen_y_ = rect.y() + rect.height() + kArrowToContentPadding; |
139 | 143 |
(...skipping 26 matching lines...) Expand all Loading... |
166 GDK_BUTTON_RELEASE_MASK); | 170 GDK_BUTTON_RELEASE_MASK); |
167 | 171 |
168 g_signal_connect(window_, "size-allocate", | 172 g_signal_connect(window_, "size-allocate", |
169 G_CALLBACK(HandleSizeAllocate), NULL); | 173 G_CALLBACK(HandleSizeAllocate), NULL); |
170 g_signal_connect(window_, "expose-event", | 174 g_signal_connect(window_, "expose-event", |
171 G_CALLBACK(HandleExpose), NULL); | 175 G_CALLBACK(HandleExpose), NULL); |
172 g_signal_connect(window_, "configure-event", | 176 g_signal_connect(window_, "configure-event", |
173 G_CALLBACK(&HandleConfigureThunk), this); | 177 G_CALLBACK(&HandleConfigureThunk), this); |
174 g_signal_connect(window_, "button-press-event", | 178 g_signal_connect(window_, "button-press-event", |
175 G_CALLBACK(&HandleButtonPressThunk), this); | 179 G_CALLBACK(&HandleButtonPressThunk), this); |
| 180 g_signal_connect(window_, "destroy", |
| 181 G_CALLBACK(&HandleDestroyThunk), this); |
176 | 182 |
177 gtk_widget_show_all(window_); | 183 gtk_widget_show_all(window_); |
| 184 // Make sure our window has focus, is brought to the top, etc. |
178 gtk_window_present(GTK_WINDOW(window_)); | 185 gtk_window_present(GTK_WINDOW(window_)); |
| 186 // We add a GTK (application level) grab. This means we will get all |
| 187 // keyboard and mouse events for our application, even if they were delivered |
| 188 // on another window. This allows us to close when the user clicks outside |
| 189 // of the info bubble. We don't use an X grab since that would steal |
| 190 // keystrokes from your window manager, prevent you from interacting with |
| 191 // other applications, etc. |
179 gtk_grab_add(window_); | 192 gtk_grab_add(window_); |
180 } | 193 } |
181 | 194 |
182 void InfoBubbleGtk::Close() { | 195 void InfoBubbleGtk::Close(bool closed_by_escape) { |
183 DCHECK(!closed_); | 196 // Notify the delegate that we're about to close. This gives the chance |
| 197 // to save state / etc from the hosted widget before it's destroyed. |
| 198 if (delegate_) |
| 199 delegate_->InfoBubbleClosing(this, closed_by_escape); |
| 200 |
184 DCHECK(window_); | 201 DCHECK(window_); |
185 gtk_widget_destroy(window_); | 202 gtk_widget_destroy(window_); |
186 window_ = NULL; | 203 // |this| has been deleted, see HandleDestroy. |
187 closed_ = true; | |
188 } | 204 } |
189 | 205 |
190 gboolean InfoBubbleGtk::HandleConfigure(GdkEventConfigure* event) { | 206 gboolean InfoBubbleGtk::HandleConfigure(GdkEventConfigure* event) { |
191 // If the window is moved someplace besides where we want it, move it back. | 207 // If the window is moved someplace besides where we want it, move it back. |
192 // TODO(deanm): In the end, I will probably remove this code and just let | 208 // TODO(deanm): In the end, I will probably remove this code and just let |
193 // the user move around the bubble like a normal dialog. I want to try | 209 // the user move around the bubble like a normal dialog. I want to try |
194 // this for now and see if it causes problems when any window managers. | 210 // this for now and see if it causes problems when any window managers. |
195 if (event->x != screen_x_ || event->y != screen_y_) | 211 if (event->x != screen_x_ || event->y != screen_y_) |
196 gtk_window_move(GTK_WINDOW(window_), screen_x_, screen_y_); | 212 gtk_window_move(GTK_WINDOW(window_), screen_x_, screen_y_); |
197 return FALSE; | 213 return FALSE; |
198 } | 214 } |
199 | 215 |
200 gboolean InfoBubbleGtk::HandleButtonPress(GdkEventButton* event) { | 216 gboolean InfoBubbleGtk::HandleButtonPress(GdkEventButton* event) { |
201 // If we got a click in our own window, that's ok. | 217 // If we got a click in our own window, that's ok. |
202 if (event->window == window_->window) | 218 if (event->window == window_->window) |
203 return FALSE; // Propagate. | 219 return FALSE; // Propagate. |
204 | 220 |
205 // Otherwise we had a click outside of our window, close ourself. | 221 // Otherwise we had a click outside of our window, close ourself. |
206 Close(); | 222 Close(); |
207 return TRUE; | 223 return TRUE; |
208 } | 224 } |
| 225 |
| 226 gboolean InfoBubbleGtk::HandleDestroy() { |
| 227 // We are self deleting, we have a destroy signal setup to catch when we |
| 228 // destroy the widget manually, or the window was closed via X. This will |
| 229 // delete the InfoBubbleGtk object. |
| 230 delete this; |
| 231 return FALSE; // Propagate. |
| 232 } |
OLD | NEW |