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

Unified Diff: chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc

Issue 113532: Implement DraggedTabGtk, the object that handles rendering either a dragged t... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h ('k') | chrome/browser/gtk/tabs/dragged_tab_gtk.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
===================================================================
--- chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc (revision 16177)
+++ chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc (working copy)
@@ -4,9 +4,11 @@
#include "chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h"
+#include "chrome/browser/gtk/tabs/dragged_tab_gtk.h"
#include "chrome/browser/gtk/tabs/tab_strip_gtk.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/gtk_util.h"
#include "chrome/common/notification_service.h"
namespace {
@@ -25,22 +27,41 @@
source_tabstrip_(source_tabstrip),
source_model_index_(source_tabstrip->GetIndexOfTab(source_tab)),
attached_tabstrip_(source_tabstrip),
+ in_destructor_(false),
last_move_screen_x_(0) {
SetDraggedContents(
source_tabstrip_->model()->GetTabContentsAt(source_model_index_));
}
DraggedTabControllerGtk::~DraggedTabControllerGtk() {
+ in_destructor_ = true;
+ // Need to delete the dragged tab here manually _before_ we reset the dragged
+ // contents to NULL, otherwise if the view is animating to its destination
+ // bounds, it won't be able to clean up properly since its cleanup routine
+ // uses GetIndexForDraggedContents, which will be invalid.
+ dragged_tab_.reset();
+ SetDraggedContents(NULL);
}
void DraggedTabControllerGtk::CaptureDragInfo(const gfx::Point& mouse_offset) {
start_screen_point_ = GetCursorScreenPoint();
mouse_offset_ = mouse_offset;
- snap_bounds_ = source_tab_->bounds();
}
void DraggedTabControllerGtk::Drag() {
- ContinueDragging();
+ if (!source_tab_)
+ return;
+
+ // Before we get to dragging anywhere, ensure that we consider ourselves
+ // attached to the source tabstrip.
+ if (source_tab_->IsVisible()) {
+ Attach(source_tabstrip_, gfx::Point());
+ }
+
+ if (!source_tab_->IsVisible()) {
+ // TODO(jhawkins): Save focus.
+ ContinueDragging();
+ }
}
bool DraggedTabControllerGtk::EndDrag(bool canceled) {
@@ -66,6 +87,8 @@
void DraggedTabControllerGtk::NavigationStateChanged(const TabContents* source,
unsigned changed_flags) {
+ if (dragged_tab_.get())
+ dragged_tab_->Update();
}
void DraggedTabControllerGtk::AddNewContents(TabContents* source,
@@ -88,6 +111,10 @@
}
void DraggedTabControllerGtk::LoadingStateChanged(TabContents* source) {
+ // TODO(jhawkins): It would be nice to respond to this message by changing the
+ // screen shot in the dragged tab.
+ if (dragged_tab_.get())
+ dragged_tab_->Update();
}
void DraggedTabControllerGtk::CloseContents(TabContents* source) {
@@ -132,6 +159,10 @@
EndDragImpl(TAB_DESTROYED);
}
+void DraggedTabControllerGtk::InitWindowCreatePoint() {
+ window_create_point_.SetPoint(mouse_offset_.x(), mouse_offset_.y());
+}
+
void DraggedTabControllerGtk::SetDraggedContents(TabContents* new_contents) {
if (dragged_contents_) {
registrar_.Remove(this,
@@ -157,6 +188,8 @@
}
void DraggedTabControllerGtk::ContinueDragging() {
+ EnsureDraggedTab();
+
// TODO(jhawkins): We don't handle the situation where the last tab is dragged
// out of a window, so we'll just go with the way Windows handles dragging for
// now.
@@ -165,7 +198,7 @@
}
void DraggedTabControllerGtk::MoveTab(const gfx::Point& screen_point) {
- gfx::Point dragged_point = GetDraggedPoint(screen_point);
+ gfx::Point dragged_tab_point = GetDraggedTabPoint(screen_point);
if (attached_tabstrip_) {
// Determine the horizontal move threshold. This is dependent on the width
@@ -183,23 +216,18 @@
TabStripModel* attached_model = attached_tabstrip_->model();
int from_index =
attached_model->GetIndexOfTabContents(dragged_contents_);
- gfx::Rect bounds = source_tab_->bounds();
+ gfx::Rect bounds = GetDraggedTabTabStripBounds(dragged_tab_point);
int to_index = GetInsertionIndexForDraggedBounds(bounds);
to_index = NormalizeIndexToAttachedTabStrip(to_index);
if (from_index != to_index) {
last_move_screen_x_ = screen_point.x();
- snap_bounds_ = attached_tabstrip_->GetTabAt(to_index)->bounds();
attached_model->MoveTabContentsAt(from_index, to_index, true);
}
}
}
- // Move the tab. There are no changes to the model if we're detached.
- gfx::Rect bounds = source_tab_->bounds();
- bounds.set_x(dragged_point.x());
- source_tab_->SetBounds(bounds);
- gtk_fixed_move(GTK_FIXED(source_tabstrip_->tabstrip_.get()),
- source_tab_->widget(), bounds.x(), bounds.y());
+ // Move the dragged tab. There are no changes to the model if we're detached.
+ dragged_tab_->MoveTo(dragged_tab_point);
}
TabStripGtk* DraggedTabControllerGtk::GetTabStripForPoint(
@@ -208,6 +236,91 @@
return source_tabstrip_;
}
+void DraggedTabControllerGtk::Attach(TabStripGtk* attached_tabstrip,
+ const gfx::Point& screen_point) {
+ attached_tabstrip_ = attached_tabstrip;
+ InitWindowCreatePoint();
+ attached_tabstrip_->GenerateIdealBounds();
+
+ TabGtk* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
+
+ // Update the tab first, so we can ask it for its bounds and determine
+ // where to insert the hidden tab.
+
+ // If this is the first time Attach is called for this drag, we're attaching
+ // to the source tabstrip, and we should assume the tab count already
+ // includes this tab since we haven't been detached yet. If we don't do this,
+ // the dragged representation will be a different size to others in the
+ // tabstrip.
+ int tab_count = attached_tabstrip_->GetTabCount();
+ if (!tab)
+ ++tab_count;
+ double unselected_width = 0, selected_width = 0;
+ attached_tabstrip_->GetDesiredTabWidths(tab_count, &unselected_width,
+ &selected_width);
+ EnsureDraggedTab();
+ dragged_tab_->Attach(static_cast<int>(selected_width));
+
+ if (!tab) {
+ // There is no tab in |attached_tabstrip| that corresponds to the dragged
+ // TabContents. We must now create one.
+
+ // Remove ourselves as the delegate now that the dragged TabContents is
+ // being inserted back into a Browser.
+ dragged_contents_->set_delegate(NULL);
+ original_delegate_ = NULL;
+
+ // Return the TabContents' to normalcy.
+ dragged_contents_->set_capturing_contents(false);
+
+ // We need to ask the tabstrip we're attached to ensure that the ideal
+ // bounds for all its tabs are correctly generated, because the calculation
+ // in GetInsertionIndexForDraggedBounds needs them to be to figure out the
+ // appropriate insertion index.
+ attached_tabstrip_->GenerateIdealBounds();
+
+ // Inserting counts as a move. We don't want the tabs to jitter when the
+ // user moves the tab immediately after attaching it.
+ last_move_screen_x_ = screen_point.x();
+
+ // Figure out where to insert the tab based on the bounds of the dragged
+ // representation and the ideal bounds of the other tabs already in the
+ // strip. ("ideal bounds" are stable even if the tabs' actual bounds are
+ // changing due to animation).
+ gfx::Rect bounds = GetDraggedTabTabStripBounds(screen_point);
+ int index = GetInsertionIndexForDraggedBounds(bounds);
+ index = std::max(std::min(index, attached_tabstrip_->model()->count()), 0);
+ attached_tabstrip_->model()->InsertTabContentsAt(index, dragged_contents_,
+ true, false);
+
+ tab = GetTabMatchingDraggedContents(attached_tabstrip_);
+ }
+ DCHECK(tab); // We should now have a tab.
+ tab->SetVisible(false);
+
+ // TODO(jhawkins): Move the corresponding window to the front.
+}
+
+void DraggedTabControllerGtk::Detach() {
+ // TODO(jhawkins): Detach the dragged tab.
+}
+
+gfx::Point DraggedTabControllerGtk::ConvertScreenPointToTabStripPoint(
+ TabStripGtk* tabstrip, const gfx::Point& screen_point) {
+ gint x, y;
+ gdk_window_get_origin(tabstrip->tabstrip_.get()->window, &x, &y);
+ return gfx::Point(screen_point.x() - x, screen_point.y() - y);
+}
+
+gfx::Rect DraggedTabControllerGtk::GetDraggedTabTabStripBounds(
+ const gfx::Point& screen_point) {
+ gfx::Point client_point =
+ ConvertScreenPointToTabStripPoint(attached_tabstrip_, screen_point);
+ gfx::Size tab_size = dragged_tab_->attached_tab_size();
+ return gfx::Rect(client_point.x(), client_point.y(),
+ tab_size.width(), tab_size.height());
+}
+
int DraggedTabControllerGtk::GetInsertionIndexForDraggedBounds(
const gfx::Rect& dragged_bounds) const {
int right_tab_x = 0;
@@ -243,19 +356,41 @@
return TabStripModel::kNoTab;
}
-gfx::Point DraggedTabControllerGtk::GetDraggedPoint(const gfx::Point& point) {
- int x = point.x() - mouse_offset_.x();
- int y = point.y() - mouse_offset_.y();
+gfx::Point DraggedTabControllerGtk::GetDraggedTabPoint(
+ const gfx::Point& screen_point) {
+ int x = screen_point.x() - mouse_offset_.x();
+ int y = screen_point.y() - mouse_offset_.y();
- // Snap the dragged tab to the tab strip.
- if (x < 0)
- x = 0;
+ // If we're not attached, we just use x and y from above.
+ if (attached_tabstrip_) {
+ gfx::Rect tabstrip_bounds =
+ gtk_util::GetWidgetScreenBounds(attached_tabstrip_->tabstrip_.get());
+ // Snap the dragged tab to the tabstrip if we are attached, detaching
+ // only when the mouse position (screen_point) exceeds the screen bounds
+ // of the tabstrip.
+ if (x < tabstrip_bounds.x() && screen_point.x() >= tabstrip_bounds.x())
+ x = tabstrip_bounds.x();
- // Make sure the tab can't be dragged off the right side of the tab strip.
- int max_x = attached_tabstrip_->bounds_.right() - source_tab_->width();
- if (x > max_x)
- x = max_x;
+ gfx::Size tab_size = dragged_tab_->attached_tab_size();
+ int vertical_drag_magnetism = tab_size.height() * 2;
+ int vertical_detach_point = tabstrip_bounds.y() - vertical_drag_magnetism;
+ if (y < tabstrip_bounds.y() && screen_point.y() >= vertical_detach_point)
+ y = tabstrip_bounds.y();
+ // Make sure the tab can't be dragged off the right side of the tabstrip
+ // unless the mouse pointer passes outside the bounds of the strip by
+ // clamping the position of the dragged window to the tabstrip width less
+ // the width of one tab until the mouse pointer (screen_point) exceeds the
+ // screen bounds of the tabstrip.
+ int max_x = tabstrip_bounds.right() - tab_size.width();
+ int max_y = tabstrip_bounds.bottom() - tab_size.height();
+ if (x > max_x && screen_point.x() <= tabstrip_bounds.right())
+ x = max_x;
+ if (y > max_y && screen_point.y() <=
+ (tabstrip_bounds.bottom() + vertical_drag_magnetism)) {
+ y = max_y;
+ }
+ }
return gfx::Point(x, y);
}
@@ -318,7 +453,7 @@
int index = attached_tabstrip_->model()->GetIndexOfTabContents(
dragged_contents_);
if (attached_tabstrip_ != source_tabstrip_) {
- // The Tab was inserted into another TabStrip. We need to put it back
+ // The tab was inserted into another tabstrip. We need to put it back
// into the original one.
attached_tabstrip_->model()->DetachTabContentsAt(index);
// TODO(beng): (Cleanup) seems like we should use Attach() for this
@@ -327,7 +462,7 @@
source_tabstrip_->model()->InsertTabContentsAt(source_model_index_,
dragged_contents_, true, false);
} else {
- // The Tab was moved within the TabStrip where the drag was initiated.
+ // The tab was moved within the tabstrip where the drag was initiated.
// Move it back to the starting location.
source_tabstrip_->model()->MoveTabContentsAt(index, source_model_index_,
true);
@@ -336,26 +471,37 @@
// TODO(beng): (Cleanup) seems like we should use Attach() for this
// somehow.
attached_tabstrip_ = source_tabstrip_;
- // The Tab was detached from the TabStrip where the drag began, and has not
- // been attached to any other TabStrip. We need to put it back into the
- // source TabStrip.
+ // The tab was detached from the tabstrip where the drag began, and has not
+ // been attached to any other tabstrip. We need to put it back into the
+ // source tabstrip.
source_tabstrip_->model()->InsertTabContentsAt(source_model_index_,
dragged_contents_, true, false);
}
+
+ source_tab_->SetVisible(true);
}
bool DraggedTabControllerGtk::CompleteDrag() {
- // We don't need to do anything other than make the Tab visible again,
+ // We don't need to do anything other than make the tab visible again,
// since the dragged tab is going away.
- gfx::Rect bounds = source_tab_->bounds();
- bounds.set_x(snap_bounds_.x());
- source_tab_->SetBounds(bounds);
- gtk_fixed_move(GTK_FIXED(source_tabstrip_->tabstrip_.get()),
- source_tab_->widget(), bounds.x(), bounds.y());
+ TabGtk* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
+ gfx::Rect rect = GetTabScreenBounds(tab);
+ dragged_tab_->AnimateToBounds(GetTabScreenBounds(tab),
+ NewCallback(this, &DraggedTabControllerGtk::OnAnimateToBoundsComplete));
return false;
}
+void DraggedTabControllerGtk::EnsureDraggedTab() {
+ if (!dragged_tab_.get()) {
+ gfx::Rect rect;
+ dragged_contents_->GetContainerBounds(&rect);
+
+ dragged_tab_.reset(new DraggedTabGtk(dragged_contents_, mouse_offset_,
+ gfx::Size(rect.width(), rect.height())));
+ }
+}
+
gfx::Point DraggedTabControllerGtk::GetCursorScreenPoint() const {
// Get default display and screen.
GdkDisplay* display = gdk_display_get_default();
@@ -366,3 +512,38 @@
return gfx::Point(x, y);
}
+
+// static
+gfx::Rect DraggedTabControllerGtk::GetTabScreenBounds(TabGtk* tab) {
+ // A hidden widget moved with gtk_fixed_move in a GtkFixed container doesn't
+ // update its allocation until after the widget is shown, so we have to use
+ // the tab bounds we keep track of.
+ int x, y;
+ x = tab->bounds().x();
+ y = tab->bounds().y();
+
+ GtkWidget* widget = tab->widget();
+ GtkWidget* parent = gtk_widget_get_parent(widget);
+ gfx::Point point = gtk_util::GetWidgetScreenPosition(parent);
+ x += point.x();
+ y += point.y();
+
+ return gfx::Rect(x, y, widget->allocation.width, widget->allocation.height);
+}
+
+void DraggedTabControllerGtk::OnAnimateToBoundsComplete() {
+ // Sometimes, for some reason, in automation we can be called back on a
+ // detach even though we aren't attached to a tabstrip. Guard against that.
+ if (attached_tabstrip_) {
+ TabGtk* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
+ if (tab) {
+ tab->SetVisible(true);
+ // Paint the tab now, otherwise there may be slight flicker between the
+ // time the dragged tab window is destroyed and we paint.
+ tab->SchedulePaint();
+ }
+ }
+
+ if (!in_destructor_)
+ source_tabstrip_->DestroyDragController();
+}
« no previous file with comments | « chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h ('k') | chrome/browser/gtk/tabs/dragged_tab_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698