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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698