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

Unified Diff: chrome/browser/ui/panels/panel_drag_gtk.cc

Issue 10020057: Resize support for detached GTK Panels. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 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
Index: chrome/browser/ui/panels/panel_drag_gtk.cc
diff --git a/chrome/browser/ui/panels/panel_drag_gtk.cc b/chrome/browser/ui/panels/panel_drag_gtk.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a08e6fea9e4d90182265cbe5d0d6031398b3b982
--- /dev/null
+++ b/chrome/browser/ui/panels/panel_drag_gtk.cc
@@ -0,0 +1,295 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/panels/panel_drag_gtk.h"
+
+#include <gdk/gdkkeysyms.h>
+
+#include "chrome/browser/ui/panels/panel.h"
+#include "chrome/browser/ui/panels/panel_constants.h"
+#include "chrome/browser/ui/panels/panel_manager.h"
+#include "ui/gfx/gtk_util.h"
+
+namespace {
+
+panel::ResizingSides GdkWindowEdgeToResizingSide(GdkWindowEdge& edge) {
dcheng 2012/04/12 00:12:45 GdkWindowEdge instead of GdkWindowEdge& ?
jennb 2012/04/12 18:00:24 Done.
+ switch (edge) {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ return panel::RESIZE_TOP_LEFT;
+ case GDK_WINDOW_EDGE_NORTH:
+ return panel::RESIZE_TOP;
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ return panel::RESIZE_TOP_RIGHT;
+ case GDK_WINDOW_EDGE_WEST:
+ return panel::RESIZE_LEFT;
+ case GDK_WINDOW_EDGE_EAST:
+ return panel::RESIZE_RIGHT;
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ return panel::RESIZE_BOTTOM_LEFT;
+ case GDK_WINDOW_EDGE_SOUTH:
+ return panel::RESIZE_BOTTOM;
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ return panel::RESIZE_BOTTOM_RIGHT;
+ default:
+ return panel::RESIZE_NONE;
+ }
+}
+
+} // namespace
+
+// Virtual base class to abstract move vs resize drag logic.
+class PanelDragDelegate {
+ public:
+ explicit PanelDragDelegate(Panel* panel) : panel_(panel) {}
+ virtual ~PanelDragDelegate() {}
Evan Stade 2012/04/12 03:25:29 add some vertical space
jennb 2012/04/12 18:00:24 Done.
+ Panel* panel() const { return panel_; }
+ PanelManager* panel_manager() const { return panel_->manager(); }
+ virtual void DragStarted(gfx::Point point) = 0;
Evan Stade 2012/04/12 03:25:29 docs for the Drag* functions (e.g. what coordinate
jennb 2012/04/12 18:00:24 Done.
+ virtual void Dragged(gfx::Point point) = 0;
+ virtual void DragEnded(bool canceled) = 0;
+ private:
+ // Weak pointer to the panel being dragged.
+ Panel* panel_;
dcheng 2012/04/12 00:12:45 Nit: DISABLE_COPY_AND_ASSIGN for these 3 classes.
jennb 2012/04/12 18:00:24 Done.
+};
+
+// Delegate for moving a panel by dragging the mouse.
+class MoveDragDelegate : public PanelDragDelegate {
Dmitry Titov 2012/04/12 00:24:44 The same name "Drag" is used in 2 different contex
jennb 2012/04/12 18:00:24 In GTK, move-drag and resize-drag is used to disti
+ public:
+ explicit MoveDragDelegate(Panel* panel)
+ : PanelDragDelegate(panel) {}
+ ~MoveDragDelegate() {}
+ void DragStarted(gfx::Point point) {
dcheng 2012/04/12 00:12:45 Do you need to use OVERRIDE here?
jennb 2012/04/12 18:00:24 Done.
+ panel_manager()->StartDragging(panel(), point);
+ }
+ void Dragged(gfx::Point point) {
+ panel_manager()->Drag(point);
+ }
+ void DragEnded(bool canceled) {
+ panel_manager()->EndDragging(canceled);
+ }
+};
+
+// Delegate for resizing a panel by dragging the mouse.
+class ResizeDragDelegate : public PanelDragDelegate {
+ public:
+ ResizeDragDelegate(Panel* panel, GdkWindowEdge& edge)
dcheng 2012/04/12 00:12:45 Ditto for mutable reference.
jennb 2012/04/12 18:00:24 Done.
+ : PanelDragDelegate(panel),
+ resizing_side_(GdkWindowEdgeToResizingSide(edge)) {}
+ ~ResizeDragDelegate() {}
+ void DragStarted(gfx::Point point) {
dcheng 2012/04/12 00:12:45 Ditto for OVERRIDE.
jennb 2012/04/12 18:00:24 Done.
+ panel_manager()->StartResizingByMouse(panel(), point, resizing_side_);
+ }
+ void Dragged(gfx::Point point) {
+ panel_manager()->ResizeByMouse(point);
+ }
+ void DragEnded(bool canceled) {
+ panel_manager()->EndResizingByMouse(canceled);
+ }
+ private:
+ // The edge from which the panel is being resized.
+ panel::ResizingSides resizing_side_;
+};
+
+// Panel drag helper for processing mouse and keyboard events while
+// the left mouse button is pressed.
+PanelDragGtk::PanelDragGtk(Panel* panel)
+ : panel_(panel),
+ drag_state_(NOT_DRAGGING),
+ initial_mouse_down_(NULL),
+ click_handler_(NULL),
+ drag_delegate_(NULL) {
+ // Create an invisible event box to receive mouse and key events.
+ drag_widget_ = gtk_event_box_new();
+ gtk_event_box_set_visible_window(GTK_EVENT_BOX(drag_widget_), FALSE);
+
+ // Connect signals for events during a drag.
+ g_signal_connect(drag_widget_, "motion-notify-event",
+ G_CALLBACK(OnMouseMoveEventThunk), this);
+ g_signal_connect(drag_widget_, "key-press-event",
+ G_CALLBACK(OnKeyPressEventThunk), this);
+ g_signal_connect(drag_widget_, "key-release-event",
+ G_CALLBACK(OnKeyReleaseEventThunk), this);
+ g_signal_connect(drag_widget_, "button-press-event",
+ G_CALLBACK(OnButtonPressEventThunk), this);
+ g_signal_connect(drag_widget_, "button-release-event",
+ G_CALLBACK(OnButtonReleaseEventThunk), this);
+ g_signal_connect(drag_widget_, "grab-broken-event",
+ G_CALLBACK(OnGrabBrokenEventThunk), this);
+}
+
+PanelDragGtk::~PanelDragGtk() {
+ EndDrag(true); // Clean up drag state.
+}
+
+bool PanelDragGtk::AssertCleanState() {
dcheng 2012/04/12 00:12:45 I think this can just return void since you always
jennb 2012/04/12 18:00:24 Done.
+ DCHECK_EQ(NOT_DRAGGING, drag_state_);
+ DCHECK(!drag_delegate_);
+ DCHECK(!initial_mouse_down_);
+ DCHECK(!click_handler_);
+ return TRUE;
+}
+
+void PanelDragGtk::InitialWindowEdgeMousePress(GdkEventButton* event,
+ GdkCursor* cursor,
+ GdkWindowEdge& edge) {
+ DCHECK(AssertCleanState());
+ drag_delegate_ = new ResizeDragDelegate(panel_, edge);
+ GrabPointerAndKeyboard(event, cursor);
+}
+
+void PanelDragGtk::InitialTitlebarMousePress(GdkEventButton* event,
+ GtkWidget* titlebar_widget) {
+ DCHECK(AssertCleanState());
+ click_handler_ = titlebar_widget;
+ drag_delegate_ = new MoveDragDelegate(panel_);
+ GrabPointerAndKeyboard(event, gfx::GetCursor(GDK_FLEUR)); // Drag cursor.
+}
+
+void PanelDragGtk::GrabPointerAndKeyboard(GdkEventButton* event,
+ GdkCursor* cursor) {
+ // Remember initial mouse event for use in determining when drag
+ // threshold has been exceeded.
+ initial_mouse_down_ = gdk_event_copy(reinterpret_cast<GdkEvent*>(event));
+
+ // Grab pointer and keyboard to make sure we have the focus and get
+ // all mouse and keyboard events during the drag.
+ GdkWindow* gdk_window = gtk_widget_get_window(drag_widget_);
+ DCHECK(gdk_window != NULL);
jennb 2012/04/11 21:59:33 Evan - any idea why this DCHECK fails if I create
Evan Stade 2012/04/12 03:25:29 I may not be understanding the question exactly bu
+ GdkGrabStatus pointer_grab_status =
+ gdk_pointer_grab(gdk_window,
Evan Stade 2012/04/12 03:25:29 2 more spaces indent
jennb 2012/04/12 18:00:24 Done.
+ TRUE,
+ GdkEventMask(GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK),
+ NULL,
+ cursor,
+ event->time);
+ GdkGrabStatus keyboard_grab_status =
+ gdk_keyboard_grab(gdk_window, TRUE, event->time);
Evan Stade 2012/04/12 03:25:29 2 more spaces indent
jennb 2012/04/12 18:00:24 Done.
+ if (pointer_grab_status != GDK_GRAB_SUCCESS ||
+ keyboard_grab_status != GDK_GRAB_SUCCESS) {
+ // Grab could fail if someone else already has the pointer/keyboard
+ // grabbed. Cancel the drag.
+ DLOG(ERROR) << "Unable to grab pointer or keyboard (pointer_status="
+ << pointer_grab_status << ", keyboard_status="
+ << keyboard_grab_status<< ")";
Evan Stade 2012/04/12 03:25:29 space before <<
jennb 2012/04/12 18:00:24 Done.
+ EndDrag(true);
+ return;
+ }
+
+ gtk_grab_add(drag_widget_);
+}
+
+void PanelDragGtk::EndDrag(bool canceled) {
+ if (initial_mouse_down_) {
+ gdk_event_free(initial_mouse_down_);
+ initial_mouse_down_ = NULL;
+ }
+
+ if (drag_delegate_) {
+ gdk_pointer_ungrab(GDK_CURRENT_TIME);
+ gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+ gtk_grab_remove(drag_widget_);
+
+ if (drag_state_ == DRAG_IN_PROGRESS) {
+ drag_delegate_->DragEnded(canceled);
+ drag_state_ = NOT_DRAGGING;
+ }
+
+ delete drag_delegate_;
+ drag_delegate_ = NULL;
+ }
+
+ click_handler_ = NULL;
+}
+
+gboolean PanelDragGtk::OnMouseMoveEvent(GtkWidget* widget,
+ GdkEventMotion* event) {
+ DCHECK(drag_delegate_);
+
+ gdouble new_x_double;
+ gdouble new_y_double;
+ gdk_event_get_root_coords(reinterpret_cast<GdkEvent*>(event),
+ &new_x_double, &new_y_double);
+ gint new_x = static_cast<gint>(new_x_double);
+ gint new_y = static_cast<gint>(new_y_double);
+
+ // Begin dragging only after mouse has moved beyond the drag threshold.
+ if (drag_state_ == NOT_DRAGGING) {
+ DCHECK(initial_mouse_down_);
+ gdouble old_x_double;
+ gdouble old_y_double;
+ gdk_event_get_root_coords(initial_mouse_down_,
+ &old_x_double, &old_y_double);
+ gint old_x = static_cast<gint>(old_x_double);
+ gint old_y = static_cast<gint>(old_y_double);
+
+ if (gtk_drag_check_threshold(drag_widget_, old_x, old_y,
+ new_x, new_y)) {
+ drag_state_ = DRAG_IN_PROGRESS;
+ drag_delegate_->DragStarted(gfx::Point(old_x, old_y));
+ gdk_event_free(initial_mouse_down_);
+ initial_mouse_down_ = NULL;
+ }
+ }
+
+ if (drag_state_ == DRAG_IN_PROGRESS)
+ drag_delegate_->Dragged(gfx::Point(new_x, new_y));
+
+ return TRUE;
+}
+
+gboolean PanelDragGtk::OnButtonPressEvent(GtkWidget* widget,
+ GdkEventButton* event) {
+ DCHECK(drag_delegate_);
+ return TRUE;
+}
+
+gboolean PanelDragGtk::OnButtonReleaseEvent(GtkWidget* widget,
+ GdkEventButton* event) {
+ DCHECK(drag_delegate_);
+
+ if (event->button == 1) {
+ // Treat release as a mouse click if drag was never started.
+ if (drag_state_ == NOT_DRAGGING && click_handler_) {
+ gtk_propagate_event(click_handler_,
+ reinterpret_cast<GdkEvent*>(event));
+ }
+ // Cleanup state regardless.
+ EndDrag(false);
+ }
+
+ return TRUE;
+}
+
+gboolean PanelDragGtk::OnKeyPressEvent(GtkWidget* widget,
+ GdkEventKey* event) {
+ DCHECK(drag_delegate_);
+ return TRUE;
+}
+
+gboolean PanelDragGtk::OnKeyReleaseEvent(GtkWidget* widget,
+ GdkEventKey* event) {
+ DCHECK(drag_delegate_);
+
+ switch (event->keyval) {
+ case GDK_Escape:
+ EndDrag(true); // Cancel drag.
+ break;
+ case GDK_Return:
+ case GDK_KP_Enter:
+ case GDK_ISO_Enter:
+ case GDK_space:
+ EndDrag(false); // Normal end.
+ break;
+ }
+ return TRUE;
+}
+
+gboolean PanelDragGtk::OnGrabBrokenEvent(GtkWidget* widget,
+ GdkEventGrabBroken* event) {
+ DCHECK(drag_delegate_);
+ EndDrag(true); // Cancel drag.
+ return TRUE;
+}

Powered by Google App Engine
This is Rietveld 408576698