OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/tabs/tab_gtk.h" | 5 #include "chrome/browser/gtk/tabs/tab_gtk.h" |
6 | 6 |
7 #include <gdk/gdkkeysyms.h> | 7 #include <gdk/gdkkeysyms.h> |
8 | 8 |
9 #include "app/gtk_dnd_util.h" | 9 #include "app/gtk_dnd_util.h" |
10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 delegate_(delegate), | 139 delegate_(delegate), |
140 closing_(false), | 140 closing_(false), |
141 last_mouse_down_(NULL), | 141 last_mouse_down_(NULL), |
142 drag_widget_(NULL), | 142 drag_widget_(NULL), |
143 title_width_(0), | 143 title_width_(0), |
144 ALLOW_THIS_IN_INITIALIZER_LIST(destroy_factory_(this)), | 144 ALLOW_THIS_IN_INITIALIZER_LIST(destroy_factory_(this)), |
145 ALLOW_THIS_IN_INITIALIZER_LIST(drag_end_factory_(this)) { | 145 ALLOW_THIS_IN_INITIALIZER_LIST(drag_end_factory_(this)) { |
146 event_box_ = gtk_event_box_new(); | 146 event_box_ = gtk_event_box_new(); |
147 gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_), FALSE); | 147 gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_), FALSE); |
148 g_signal_connect(event_box_, "button-press-event", | 148 g_signal_connect(event_box_, "button-press-event", |
149 G_CALLBACK(OnButtonPressEvent), this); | 149 G_CALLBACK(OnButtonPressEventThunk), this); |
150 g_signal_connect(event_box_, "button-release-event", | 150 g_signal_connect(event_box_, "button-release-event", |
151 G_CALLBACK(OnButtonReleaseEvent), this); | 151 G_CALLBACK(OnButtonReleaseEventThunk), this); |
152 g_signal_connect(event_box_, "enter-notify-event", | 152 g_signal_connect(event_box_, "enter-notify-event", |
153 G_CALLBACK(OnEnterNotifyEvent), this); | 153 G_CALLBACK(OnEnterNotifyEventThunk), this); |
154 g_signal_connect(event_box_, "leave-notify-event", | 154 g_signal_connect(event_box_, "leave-notify-event", |
155 G_CALLBACK(OnLeaveNotifyEvent), this); | 155 G_CALLBACK(OnLeaveNotifyEventThunk), this); |
156 gtk_widget_add_events(event_box_, | 156 gtk_widget_add_events(event_box_, |
157 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | | 157 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | |
158 GDK_LEAVE_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); | 158 GDK_LEAVE_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); |
159 gtk_container_add(GTK_CONTAINER(event_box_), TabRendererGtk::widget()); | 159 gtk_container_add(GTK_CONTAINER(event_box_), TabRendererGtk::widget()); |
160 gtk_widget_show_all(event_box_); | 160 gtk_widget_show_all(event_box_); |
161 } | 161 } |
162 | 162 |
163 TabGtk::~TabGtk() { | 163 TabGtk::~TabGtk() { |
164 if (drag_widget_) { | 164 if (drag_widget_) { |
165 // Shadow the drag grab so the grab terminates. We could do this using any | 165 // Shadow the drag grab so the grab terminates. We could do this using any |
166 // widget, |drag_widget_| is just convenient. | 166 // widget, |drag_widget_| is just convenient. |
167 gtk_grab_add(drag_widget_); | 167 gtk_grab_add(drag_widget_); |
168 gtk_grab_remove(drag_widget_); | 168 gtk_grab_remove(drag_widget_); |
169 DestroyDragWidget(); | 169 DestroyDragWidget(); |
170 } | 170 } |
171 | 171 |
172 if (menu_controller_.get()) { | 172 if (menu_controller_.get()) { |
173 // The menu is showing. Close the menu. | 173 // The menu is showing. Close the menu. |
174 menu_controller_->Cancel(); | 174 menu_controller_->Cancel(); |
175 | 175 |
176 // Invoke this so that we hide the highlight. | 176 // Invoke this so that we hide the highlight. |
177 ContextMenuClosed(); | 177 ContextMenuClosed(); |
178 } | 178 } |
179 } | 179 } |
180 | 180 |
181 // static | 181 gboolean TabGtk::OnButtonPressEvent(GtkWidget* widget, GdkEventButton* event) { |
182 gboolean TabGtk::OnButtonPressEvent(GtkWidget* widget, GdkEventButton* event, | |
183 TabGtk* tab) { | |
184 // Every button press ensures either a button-release-event or a drag-fail | 182 // Every button press ensures either a button-release-event or a drag-fail |
185 // signal for |widget|. | 183 // signal for |widget|. |
186 if (event->button == 1 && event->type == GDK_BUTTON_PRESS) { | 184 if (event->button == 1 && event->type == GDK_BUTTON_PRESS) { |
187 // Store whether or not we were selected just now... we only want to be | 185 // Store whether or not we were selected just now... we only want to be |
188 // able to drag foreground tabs, so we don't start dragging the tab if | 186 // able to drag foreground tabs, so we don't start dragging the tab if |
189 // it was in the background. | 187 // it was in the background. |
190 bool just_selected = !tab->IsSelected(); | 188 bool just_selected = !IsSelected(); |
191 if (just_selected) { | 189 if (just_selected) { |
192 tab->delegate_->SelectTab(tab); | 190 delegate_->SelectTab(this); |
193 } | 191 } |
194 | 192 |
195 // Hook into the message loop to handle dragging. | 193 // Hook into the message loop to handle dragging. |
196 tab->observer_.reset(new TabGtkObserverHelper(tab)); | 194 observer_.reset(new TabGtkObserverHelper(this)); |
197 | 195 |
198 // Store the button press event, used to initiate a drag. | 196 // Store the button press event, used to initiate a drag. |
199 tab->last_mouse_down_ = gdk_event_copy(reinterpret_cast<GdkEvent*>(event)); | 197 last_mouse_down_ = gdk_event_copy(reinterpret_cast<GdkEvent*>(event)); |
200 } else if (event->button == 3) { | 198 } else if (event->button == 3) { |
201 // Only show the context menu if the left mouse button isn't down (i.e., | 199 // Only show the context menu if the left mouse button isn't down (i.e., |
202 // the user might want to drag instead). | 200 // the user might want to drag instead). |
203 if (!tab->last_mouse_down_) | 201 if (!last_mouse_down_) |
204 tab->ShowContextMenu(); | 202 ShowContextMenu(); |
205 } | 203 } |
206 | 204 |
207 return TRUE; | 205 return TRUE; |
208 } | 206 } |
209 | 207 |
210 // static | 208 gboolean TabGtk::OnButtonReleaseEvent(GtkWidget* widget, |
211 gboolean TabGtk::OnButtonReleaseEvent(GtkWidget* widget, GdkEventButton* event, | 209 GdkEventButton* event) { |
212 TabGtk* tab) { | |
213 if (event->button == 1) { | 210 if (event->button == 1) { |
214 tab->observer_.reset(); | 211 observer_.reset(); |
215 | 212 |
216 if (tab->last_mouse_down_) { | 213 if (last_mouse_down_) { |
217 gdk_event_free(tab->last_mouse_down_); | 214 gdk_event_free(last_mouse_down_); |
218 tab->last_mouse_down_ = NULL; | 215 last_mouse_down_ = NULL; |
219 } | 216 } |
220 } | 217 } |
221 | 218 |
222 // Middle mouse up means close the tab, but only if the mouse is over it | 219 // Middle mouse up means close the tab, but only if the mouse is over it |
223 // (like a button). | 220 // (like a button). |
224 if (event->button == 2 && | 221 if (event->button == 2 && |
225 event->x >= 0 && event->y >= 0 && | 222 event->x >= 0 && event->y >= 0 && |
226 event->x < widget->allocation.width && | 223 event->x < widget->allocation.width && |
227 event->y < widget->allocation.height) { | 224 event->y < widget->allocation.height) { |
228 // If the user is currently holding the left mouse button down but hasn't | 225 // If the user is currently holding the left mouse button down but hasn't |
229 // moved the mouse yet, a drag hasn't started yet. In that case, clean up | 226 // moved the mouse yet, a drag hasn't started yet. In that case, clean up |
230 // some state before closing the tab to avoid a crash. Once the drag has | 227 // some state before closing the tab to avoid a crash. Once the drag has |
231 // started, we don't get the middle mouse click here. | 228 // started, we don't get the middle mouse click here. |
232 if (tab->last_mouse_down_) { | 229 if (last_mouse_down_) { |
233 DCHECK(!tab->drag_widget_); | 230 DCHECK(!drag_widget_); |
234 tab->observer_.reset(); | 231 observer_.reset(); |
235 gdk_event_free(tab->last_mouse_down_); | 232 gdk_event_free(last_mouse_down_); |
236 tab->last_mouse_down_ = NULL; | 233 last_mouse_down_ = NULL; |
237 } | 234 } |
238 tab->delegate_->CloseTab(tab); | 235 delegate_->CloseTab(this); |
239 } | 236 } |
240 | 237 |
241 return TRUE; | 238 return TRUE; |
242 } | 239 } |
243 | 240 |
244 // static | |
245 gboolean TabGtk::OnDragFailed(GtkWidget* widget, GdkDragContext* context, | 241 gboolean TabGtk::OnDragFailed(GtkWidget* widget, GdkDragContext* context, |
246 GtkDragResult result, | 242 GtkDragResult result) { |
247 TabGtk* tab) { | |
248 bool canceled = (result == GTK_DRAG_RESULT_USER_CANCELLED); | 243 bool canceled = (result == GTK_DRAG_RESULT_USER_CANCELLED); |
249 tab->EndDrag(canceled); | 244 EndDrag(canceled); |
250 return TRUE; | 245 return TRUE; |
251 } | 246 } |
252 | 247 |
253 // static | 248 gboolean TabGtk::OnDragButtonReleased(GtkWidget* widget, |
254 gboolean TabGtk::OnDragButtonReleased(GtkWidget* widget, GdkEventButton* button, | 249 GdkEventButton* button) { |
255 TabGtk* tab) { | |
256 // We always get this event when gtk is releasing the grab and ending the | 250 // We always get this event when gtk is releasing the grab and ending the |
257 // drag. However, if the user ended the drag with space or enter, we don't | 251 // drag. However, if the user ended the drag with space or enter, we don't |
258 // get a follow up event to tell us the drag has finished (either a | 252 // get a follow up event to tell us the drag has finished (either a |
259 // drag-failed or a drag-end). So we post a task to manually end the drag. | 253 // drag-failed or a drag-end). So we post a task to manually end the drag. |
260 // If GTK+ does send the drag-failed or drag-end event, we cancel the task. | 254 // If GTK+ does send the drag-failed or drag-end event, we cancel the task. |
261 MessageLoop::current()->PostTask(FROM_HERE, | 255 MessageLoop::current()->PostTask(FROM_HERE, |
262 tab->drag_end_factory_.NewRunnableMethod(&TabGtk::EndDrag, false)); | 256 drag_end_factory_.NewRunnableMethod(&TabGtk::EndDrag, false)); |
263 return TRUE; | 257 return TRUE; |
264 } | 258 } |
265 | 259 |
266 // static | 260 void TabGtk::OnDragBegin(GtkWidget* widget, GdkDragContext* context) { |
267 void TabGtk::OnDragBegin(GtkWidget* widget, GdkDragContext* context, | |
268 TabGtk* tab) { | |
269 GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1); | 261 GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1); |
270 gtk_drag_set_icon_pixbuf(context, pixbuf, 0, 0); | 262 gtk_drag_set_icon_pixbuf(context, pixbuf, 0, 0); |
271 g_object_unref(pixbuf); | 263 g_object_unref(pixbuf); |
272 } | 264 } |
273 | 265 |
274 /////////////////////////////////////////////////////////////////////////////// | 266 /////////////////////////////////////////////////////////////////////////////// |
275 // TabGtk, MessageLoop::Observer implementation: | 267 // TabGtk, MessageLoop::Observer implementation: |
276 | 268 |
277 void TabGtk::WillProcessEvent(GdkEvent* event) { | 269 void TabGtk::WillProcessEvent(GdkEvent* event) { |
278 // Nothing to do. | 270 // Nothing to do. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 gtk_widget_set_tooltip_text(widget(), WideToUTF8(GetTitle()).c_str()); | 353 gtk_widget_set_tooltip_text(widget(), WideToUTF8(GetTitle()).c_str()); |
362 } else { | 354 } else { |
363 gtk_widget_set_has_tooltip(widget(), FALSE); | 355 gtk_widget_set_has_tooltip(widget(), FALSE); |
364 } | 356 } |
365 } | 357 } |
366 | 358 |
367 void TabGtk::CreateDragWidget() { | 359 void TabGtk::CreateDragWidget() { |
368 DCHECK(!drag_widget_); | 360 DCHECK(!drag_widget_); |
369 drag_widget_ = gtk_invisible_new(); | 361 drag_widget_ = gtk_invisible_new(); |
370 g_signal_connect(drag_widget_, "drag-failed", | 362 g_signal_connect(drag_widget_, "drag-failed", |
371 G_CALLBACK(OnDragFailed), this); | 363 G_CALLBACK(OnDragFailedThunk), this); |
372 g_signal_connect(drag_widget_, "button-release-event", | 364 g_signal_connect(drag_widget_, "button-release-event", |
373 G_CALLBACK(OnDragButtonReleased), this); | 365 G_CALLBACK(OnDragButtonReleasedThunk), this); |
374 g_signal_connect_after(drag_widget_, "drag-begin", | 366 g_signal_connect_after(drag_widget_, "drag-begin", |
375 G_CALLBACK(OnDragBegin), this); | 367 G_CALLBACK(OnDragBeginThunk), this); |
376 } | 368 } |
377 | 369 |
378 void TabGtk::DestroyDragWidget() { | 370 void TabGtk::DestroyDragWidget() { |
379 if (drag_widget_) { | 371 if (drag_widget_) { |
380 gtk_widget_destroy(drag_widget_); | 372 gtk_widget_destroy(drag_widget_); |
381 drag_widget_ = NULL; | 373 drag_widget_ = NULL; |
382 } | 374 } |
383 } | 375 } |
384 | 376 |
385 void TabGtk::StartDragging(gfx::Point drag_offset) { | 377 void TabGtk::StartDragging(gfx::Point drag_offset) { |
(...skipping 23 matching lines...) Expand all Loading... |
409 gdk_event_free(last_mouse_down_); | 401 gdk_event_free(last_mouse_down_); |
410 last_mouse_down_ = NULL; | 402 last_mouse_down_ = NULL; |
411 } | 403 } |
412 | 404 |
413 // Notify the drag helper that we're done with any potential drag operations. | 405 // Notify the drag helper that we're done with any potential drag operations. |
414 // Clean up the drag helper, which is re-created on the next mouse press. | 406 // Clean up the drag helper, which is re-created on the next mouse press. |
415 delegate_->EndDrag(canceled); | 407 delegate_->EndDrag(canceled); |
416 | 408 |
417 observer_.reset(); | 409 observer_.reset(); |
418 } | 410 } |
OLD | NEW |