| 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 |