Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/panels/panel_drag_gtk.h" | |
| 6 | |
| 7 #include <gdk/gdkkeysyms.h> | |
| 8 | |
| 9 #include "chrome/browser/ui/panels/panel.h" | |
| 10 #include "chrome/browser/ui/panels/panel_constants.h" | |
| 11 #include "chrome/browser/ui/panels/panel_manager.h" | |
| 12 #include "ui/gfx/gtk_util.h" | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 panel::ResizingSides GdkWindowEdgeToResizingSide(GdkWindowEdge& edge) { | |
|
dcheng
2012/04/12 00:12:45
GdkWindowEdge instead of GdkWindowEdge& ?
jennb
2012/04/12 18:00:24
Done.
| |
| 17 switch (edge) { | |
| 18 case GDK_WINDOW_EDGE_NORTH_WEST: | |
| 19 return panel::RESIZE_TOP_LEFT; | |
| 20 case GDK_WINDOW_EDGE_NORTH: | |
| 21 return panel::RESIZE_TOP; | |
| 22 case GDK_WINDOW_EDGE_NORTH_EAST: | |
| 23 return panel::RESIZE_TOP_RIGHT; | |
| 24 case GDK_WINDOW_EDGE_WEST: | |
| 25 return panel::RESIZE_LEFT; | |
| 26 case GDK_WINDOW_EDGE_EAST: | |
| 27 return panel::RESIZE_RIGHT; | |
| 28 case GDK_WINDOW_EDGE_SOUTH_WEST: | |
| 29 return panel::RESIZE_BOTTOM_LEFT; | |
| 30 case GDK_WINDOW_EDGE_SOUTH: | |
| 31 return panel::RESIZE_BOTTOM; | |
| 32 case GDK_WINDOW_EDGE_SOUTH_EAST: | |
| 33 return panel::RESIZE_BOTTOM_RIGHT; | |
| 34 default: | |
| 35 return panel::RESIZE_NONE; | |
| 36 } | |
| 37 } | |
| 38 | |
| 39 } // namespace | |
| 40 | |
| 41 // Virtual base class to abstract move vs resize drag logic. | |
| 42 class PanelDragDelegate { | |
| 43 public: | |
| 44 explicit PanelDragDelegate(Panel* panel) : panel_(panel) {} | |
| 45 virtual ~PanelDragDelegate() {} | |
|
Evan Stade
2012/04/12 03:25:29
add some vertical space
jennb
2012/04/12 18:00:24
Done.
| |
| 46 Panel* panel() const { return panel_; } | |
| 47 PanelManager* panel_manager() const { return panel_->manager(); } | |
| 48 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.
| |
| 49 virtual void Dragged(gfx::Point point) = 0; | |
| 50 virtual void DragEnded(bool canceled) = 0; | |
| 51 private: | |
| 52 // Weak pointer to the panel being dragged. | |
| 53 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.
| |
| 54 }; | |
| 55 | |
| 56 // Delegate for moving a panel by dragging the mouse. | |
| 57 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
| |
| 58 public: | |
| 59 explicit MoveDragDelegate(Panel* panel) | |
| 60 : PanelDragDelegate(panel) {} | |
| 61 ~MoveDragDelegate() {} | |
| 62 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.
| |
| 63 panel_manager()->StartDragging(panel(), point); | |
| 64 } | |
| 65 void Dragged(gfx::Point point) { | |
| 66 panel_manager()->Drag(point); | |
| 67 } | |
| 68 void DragEnded(bool canceled) { | |
| 69 panel_manager()->EndDragging(canceled); | |
| 70 } | |
| 71 }; | |
| 72 | |
| 73 // Delegate for resizing a panel by dragging the mouse. | |
| 74 class ResizeDragDelegate : public PanelDragDelegate { | |
| 75 public: | |
| 76 ResizeDragDelegate(Panel* panel, GdkWindowEdge& edge) | |
|
dcheng
2012/04/12 00:12:45
Ditto for mutable reference.
jennb
2012/04/12 18:00:24
Done.
| |
| 77 : PanelDragDelegate(panel), | |
| 78 resizing_side_(GdkWindowEdgeToResizingSide(edge)) {} | |
| 79 ~ResizeDragDelegate() {} | |
| 80 void DragStarted(gfx::Point point) { | |
|
dcheng
2012/04/12 00:12:45
Ditto for OVERRIDE.
jennb
2012/04/12 18:00:24
Done.
| |
| 81 panel_manager()->StartResizingByMouse(panel(), point, resizing_side_); | |
| 82 } | |
| 83 void Dragged(gfx::Point point) { | |
| 84 panel_manager()->ResizeByMouse(point); | |
| 85 } | |
| 86 void DragEnded(bool canceled) { | |
| 87 panel_manager()->EndResizingByMouse(canceled); | |
| 88 } | |
| 89 private: | |
| 90 // The edge from which the panel is being resized. | |
| 91 panel::ResizingSides resizing_side_; | |
| 92 }; | |
| 93 | |
| 94 // Panel drag helper for processing mouse and keyboard events while | |
| 95 // the left mouse button is pressed. | |
| 96 PanelDragGtk::PanelDragGtk(Panel* panel) | |
| 97 : panel_(panel), | |
| 98 drag_state_(NOT_DRAGGING), | |
| 99 initial_mouse_down_(NULL), | |
| 100 click_handler_(NULL), | |
| 101 drag_delegate_(NULL) { | |
| 102 // Create an invisible event box to receive mouse and key events. | |
| 103 drag_widget_ = gtk_event_box_new(); | |
| 104 gtk_event_box_set_visible_window(GTK_EVENT_BOX(drag_widget_), FALSE); | |
| 105 | |
| 106 // Connect signals for events during a drag. | |
| 107 g_signal_connect(drag_widget_, "motion-notify-event", | |
| 108 G_CALLBACK(OnMouseMoveEventThunk), this); | |
| 109 g_signal_connect(drag_widget_, "key-press-event", | |
| 110 G_CALLBACK(OnKeyPressEventThunk), this); | |
| 111 g_signal_connect(drag_widget_, "key-release-event", | |
| 112 G_CALLBACK(OnKeyReleaseEventThunk), this); | |
| 113 g_signal_connect(drag_widget_, "button-press-event", | |
| 114 G_CALLBACK(OnButtonPressEventThunk), this); | |
| 115 g_signal_connect(drag_widget_, "button-release-event", | |
| 116 G_CALLBACK(OnButtonReleaseEventThunk), this); | |
| 117 g_signal_connect(drag_widget_, "grab-broken-event", | |
| 118 G_CALLBACK(OnGrabBrokenEventThunk), this); | |
| 119 } | |
| 120 | |
| 121 PanelDragGtk::~PanelDragGtk() { | |
| 122 EndDrag(true); // Clean up drag state. | |
| 123 } | |
| 124 | |
| 125 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.
| |
| 126 DCHECK_EQ(NOT_DRAGGING, drag_state_); | |
| 127 DCHECK(!drag_delegate_); | |
| 128 DCHECK(!initial_mouse_down_); | |
| 129 DCHECK(!click_handler_); | |
| 130 return TRUE; | |
| 131 } | |
| 132 | |
| 133 void PanelDragGtk::InitialWindowEdgeMousePress(GdkEventButton* event, | |
| 134 GdkCursor* cursor, | |
| 135 GdkWindowEdge& edge) { | |
| 136 DCHECK(AssertCleanState()); | |
| 137 drag_delegate_ = new ResizeDragDelegate(panel_, edge); | |
| 138 GrabPointerAndKeyboard(event, cursor); | |
| 139 } | |
| 140 | |
| 141 void PanelDragGtk::InitialTitlebarMousePress(GdkEventButton* event, | |
| 142 GtkWidget* titlebar_widget) { | |
| 143 DCHECK(AssertCleanState()); | |
| 144 click_handler_ = titlebar_widget; | |
| 145 drag_delegate_ = new MoveDragDelegate(panel_); | |
| 146 GrabPointerAndKeyboard(event, gfx::GetCursor(GDK_FLEUR)); // Drag cursor. | |
| 147 } | |
| 148 | |
| 149 void PanelDragGtk::GrabPointerAndKeyboard(GdkEventButton* event, | |
| 150 GdkCursor* cursor) { | |
| 151 // Remember initial mouse event for use in determining when drag | |
| 152 // threshold has been exceeded. | |
| 153 initial_mouse_down_ = gdk_event_copy(reinterpret_cast<GdkEvent*>(event)); | |
| 154 | |
| 155 // Grab pointer and keyboard to make sure we have the focus and get | |
| 156 // all mouse and keyboard events during the drag. | |
| 157 GdkWindow* gdk_window = gtk_widget_get_window(drag_widget_); | |
| 158 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
| |
| 159 GdkGrabStatus pointer_grab_status = | |
| 160 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.
| |
| 161 TRUE, | |
| 162 GdkEventMask(GDK_BUTTON_PRESS_MASK | | |
| 163 GDK_BUTTON_RELEASE_MASK | | |
| 164 GDK_POINTER_MOTION_MASK), | |
| 165 NULL, | |
| 166 cursor, | |
| 167 event->time); | |
| 168 GdkGrabStatus keyboard_grab_status = | |
| 169 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.
| |
| 170 if (pointer_grab_status != GDK_GRAB_SUCCESS || | |
| 171 keyboard_grab_status != GDK_GRAB_SUCCESS) { | |
| 172 // Grab could fail if someone else already has the pointer/keyboard | |
| 173 // grabbed. Cancel the drag. | |
| 174 DLOG(ERROR) << "Unable to grab pointer or keyboard (pointer_status=" | |
| 175 << pointer_grab_status << ", keyboard_status=" | |
| 176 << keyboard_grab_status<< ")"; | |
|
Evan Stade
2012/04/12 03:25:29
space before <<
jennb
2012/04/12 18:00:24
Done.
| |
| 177 EndDrag(true); | |
| 178 return; | |
| 179 } | |
| 180 | |
| 181 gtk_grab_add(drag_widget_); | |
| 182 } | |
| 183 | |
| 184 void PanelDragGtk::EndDrag(bool canceled) { | |
| 185 if (initial_mouse_down_) { | |
| 186 gdk_event_free(initial_mouse_down_); | |
| 187 initial_mouse_down_ = NULL; | |
| 188 } | |
| 189 | |
| 190 if (drag_delegate_) { | |
| 191 gdk_pointer_ungrab(GDK_CURRENT_TIME); | |
| 192 gdk_keyboard_ungrab(GDK_CURRENT_TIME); | |
| 193 gtk_grab_remove(drag_widget_); | |
| 194 | |
| 195 if (drag_state_ == DRAG_IN_PROGRESS) { | |
| 196 drag_delegate_->DragEnded(canceled); | |
| 197 drag_state_ = NOT_DRAGGING; | |
| 198 } | |
| 199 | |
| 200 delete drag_delegate_; | |
| 201 drag_delegate_ = NULL; | |
| 202 } | |
| 203 | |
| 204 click_handler_ = NULL; | |
| 205 } | |
| 206 | |
| 207 gboolean PanelDragGtk::OnMouseMoveEvent(GtkWidget* widget, | |
| 208 GdkEventMotion* event) { | |
| 209 DCHECK(drag_delegate_); | |
| 210 | |
| 211 gdouble new_x_double; | |
| 212 gdouble new_y_double; | |
| 213 gdk_event_get_root_coords(reinterpret_cast<GdkEvent*>(event), | |
| 214 &new_x_double, &new_y_double); | |
| 215 gint new_x = static_cast<gint>(new_x_double); | |
| 216 gint new_y = static_cast<gint>(new_y_double); | |
| 217 | |
| 218 // Begin dragging only after mouse has moved beyond the drag threshold. | |
| 219 if (drag_state_ == NOT_DRAGGING) { | |
| 220 DCHECK(initial_mouse_down_); | |
| 221 gdouble old_x_double; | |
| 222 gdouble old_y_double; | |
| 223 gdk_event_get_root_coords(initial_mouse_down_, | |
| 224 &old_x_double, &old_y_double); | |
| 225 gint old_x = static_cast<gint>(old_x_double); | |
| 226 gint old_y = static_cast<gint>(old_y_double); | |
| 227 | |
| 228 if (gtk_drag_check_threshold(drag_widget_, old_x, old_y, | |
| 229 new_x, new_y)) { | |
| 230 drag_state_ = DRAG_IN_PROGRESS; | |
| 231 drag_delegate_->DragStarted(gfx::Point(old_x, old_y)); | |
| 232 gdk_event_free(initial_mouse_down_); | |
| 233 initial_mouse_down_ = NULL; | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 if (drag_state_ == DRAG_IN_PROGRESS) | |
| 238 drag_delegate_->Dragged(gfx::Point(new_x, new_y)); | |
| 239 | |
| 240 return TRUE; | |
| 241 } | |
| 242 | |
| 243 gboolean PanelDragGtk::OnButtonPressEvent(GtkWidget* widget, | |
| 244 GdkEventButton* event) { | |
| 245 DCHECK(drag_delegate_); | |
| 246 return TRUE; | |
| 247 } | |
| 248 | |
| 249 gboolean PanelDragGtk::OnButtonReleaseEvent(GtkWidget* widget, | |
| 250 GdkEventButton* event) { | |
| 251 DCHECK(drag_delegate_); | |
| 252 | |
| 253 if (event->button == 1) { | |
| 254 // Treat release as a mouse click if drag was never started. | |
| 255 if (drag_state_ == NOT_DRAGGING && click_handler_) { | |
| 256 gtk_propagate_event(click_handler_, | |
| 257 reinterpret_cast<GdkEvent*>(event)); | |
| 258 } | |
| 259 // Cleanup state regardless. | |
| 260 EndDrag(false); | |
| 261 } | |
| 262 | |
| 263 return TRUE; | |
| 264 } | |
| 265 | |
| 266 gboolean PanelDragGtk::OnKeyPressEvent(GtkWidget* widget, | |
| 267 GdkEventKey* event) { | |
| 268 DCHECK(drag_delegate_); | |
| 269 return TRUE; | |
| 270 } | |
| 271 | |
| 272 gboolean PanelDragGtk::OnKeyReleaseEvent(GtkWidget* widget, | |
| 273 GdkEventKey* event) { | |
| 274 DCHECK(drag_delegate_); | |
| 275 | |
| 276 switch (event->keyval) { | |
| 277 case GDK_Escape: | |
| 278 EndDrag(true); // Cancel drag. | |
| 279 break; | |
| 280 case GDK_Return: | |
| 281 case GDK_KP_Enter: | |
| 282 case GDK_ISO_Enter: | |
| 283 case GDK_space: | |
| 284 EndDrag(false); // Normal end. | |
| 285 break; | |
| 286 } | |
| 287 return TRUE; | |
| 288 } | |
| 289 | |
| 290 gboolean PanelDragGtk::OnGrabBrokenEvent(GtkWidget* widget, | |
| 291 GdkEventGrabBroken* event) { | |
| 292 DCHECK(drag_delegate_); | |
| 293 EndDrag(true); // Cancel drag. | |
| 294 return TRUE; | |
| 295 } | |
| OLD | NEW |