summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-19 23:26:44 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-19 23:26:44 +0000
commitfaeaa946158d500de841248de8a0caab3d597309 (patch)
tree684918c2a0e34fe8f3c6cbbdf9ed2ab8ba8e0217 /views
parent2c0494456175ace10c2d83ddaab9aa4f5b0ed0cd (diff)
downloadchromium_src-faeaa946158d500de841248de8a0caab3d597309.zip
chromium_src-faeaa946158d500de841248de8a0caab3d597309.tar.gz
chromium_src-faeaa946158d500de841248de8a0caab3d597309.tar.bz2
Fixes delivery of mouse events in WidgetGtk. Also fixes GetRootWidget
and GetWidget to match windows. BUG=none TEST=none Review URL: http://codereview.chromium.org/113603 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16431 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/widget/widget_gtk.cc184
-rw-r--r--views/widget/widget_gtk.h23
-rw-r--r--views/window/window_gtk.cc1
3 files changed, 156 insertions, 52 deletions
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index c130c58..0b24657 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -28,11 +28,35 @@ static void GetWidgetPositionOnScreen(GtkWidget* widget, int* x, int *y) {
}
}
+// Returns the view::Event::flags for a GdkEventButton.
+static int GetFlagsForEventButton(const GdkEventButton& event) {
+ int flags = Event::GetFlagsFromGdkState(event.state);
+ switch (event.button) {
+ case 1:
+ flags |= Event::EF_LEFT_BUTTON_DOWN;
+ break;
+ case 2:
+ flags |= Event::EF_MIDDLE_BUTTON_DOWN;
+ break;
+ case 3:
+ flags |= Event::EF_RIGHT_BUTTON_DOWN;
+ break;
+ default:
+ // We only deal with 1-3.
+ break;
+ }
+ if (event.type == GDK_2BUTTON_PRESS)
+ flags |= MouseEvent::EF_IS_DOUBLE_CLICK;
+ return flags;
+}
+
WidgetGtk::WidgetGtk(Type type)
- : type_(type),
+ : is_window_(false),
+ type_(type),
widget_(NULL),
child_widget_parent_(NULL),
is_mouse_down_(false),
+ has_capture_(false),
last_mouse_event_was_move_(false) {
}
@@ -42,7 +66,7 @@ WidgetGtk::~WidgetGtk() {
gtk_widget_destroy(widget_);
child_widget_parent_ = widget_ = NULL;
}
- // MessageLoopForUI::current()->RemoveObserver(this);
+ MessageLoopForUI::current()->RemoveObserver(this);
}
void WidgetGtk::Init(const gfx::Rect& bounds,
@@ -74,7 +98,7 @@ void WidgetGtk::Init(const gfx::Rect& bounds,
SetRootViewForWidget(widget_, root_view_.get());
- // MessageLoopForUI::current()->AddObserver(this);
+ MessageLoopForUI::current()->AddObserver(this);
g_signal_connect_after(G_OBJECT(child_widget_parent_), "size_allocate",
G_CALLBACK(CallSizeAllocate), NULL);
@@ -94,6 +118,12 @@ void WidgetGtk::Init(const gfx::Rect& bounds,
G_CALLBACK(CallFocusIn), NULL);
g_signal_connect(G_OBJECT(child_widget_parent_), "focus_out_event",
G_CALLBACK(CallFocusOut), NULL);
+ g_signal_connect(G_OBJECT(child_widget_parent_), "grab_broke_event",
+ G_CALLBACK(CallGrabBrokeEvent), NULL);
+ g_signal_connect(G_OBJECT(child_widget_parent_), "grab_notify",
+ G_CALLBACK(CallGrabNotify), NULL);
+ g_signal_connect(G_OBJECT(child_widget_parent_), "focus_out_event",
+ G_CALLBACK(CallFocusOut), NULL);
g_signal_connect(G_OBJECT(child_widget_parent_), "key_press_event",
G_CALLBACK(CallKeyPress), NULL);
g_signal_connect(G_OBJECT(child_widget_parent_), "key_release_event",
@@ -187,8 +217,13 @@ RootView* WidgetGtk::GetRootView() {
}
Widget* WidgetGtk::GetRootWidget() const {
- NOTIMPLEMENTED();
- return NULL;
+ GtkWidget* parent = widget_;
+ GtkWidget* last_parent = parent;
+ while (parent) {
+ last_parent = parent;
+ parent = gtk_widget_get_parent(parent);
+ }
+ return last_parent ? GetViewForNative(last_parent) : NULL;
}
bool WidgetGtk::IsVisible() const {
@@ -215,6 +250,11 @@ Window* WidgetGtk::GetWindow() {
return GetWindowImpl(widget_);
}
+void WidgetGtk::DidProcessEvent(GdkEvent* event) {
+ if (root_view_->NeedsPainting(true))
+ PaintNow(root_view_->GetScheduledPaintRect());
+}
+
const Window* WidgetGtk::GetWindow() const {
return GetWindowImpl(widget_);
}
@@ -249,6 +289,19 @@ void WidgetGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {
}
gboolean WidgetGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) {
+ if (has_capture_ && is_mouse_down_) {
+ last_mouse_event_was_move_ = false;
+ int flags = Event::GetFlagsFromGdkState(event->state);
+ if (event->state & GDK_BUTTON1_MASK)
+ flags |= Event::EF_LEFT_BUTTON_DOWN;
+ if (event->state & GDK_BUTTON2_MASK)
+ flags |= Event::EF_MIDDLE_BUTTON_DOWN;
+ if (event->state & GDK_BUTTON3_MASK)
+ flags |= Event::EF_RIGHT_BUTTON_DOWN;
+ MouseEvent mouse_drag(Event::ET_MOUSE_DRAGGED, event->x, event->y, flags);
+ root_view_->OnMouseDragged(mouse_drag);
+ return true;
+ }
gfx::Point screen_loc(event->x_root, event->y_root);
if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() &&
last_mouse_move_y_ == screen_loc.y()) {
@@ -258,10 +311,14 @@ gboolean WidgetGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) {
last_mouse_move_x_ = screen_loc.x();
last_mouse_move_y_ = screen_loc.y();
last_mouse_event_was_move_ = true;
- MouseEvent mouse_move(Event::ET_MOUSE_MOVED,
- event->x,
- event->y,
- Event::GetFlagsFromGdkState(event->state));
+ int flags = Event::GetFlagsFromGdkState(event->state);
+ if (event->state & GDK_BUTTON1_MASK)
+ flags |= Event::EF_LEFT_BUTTON_DOWN;
+ if (event->state & GDK_BUTTON2_MASK)
+ flags |= Event::EF_MIDDLE_BUTTON_DOWN;
+ if (event->state & GDK_BUTTON3_MASK)
+ flags |= Event::EF_RIGHT_BUTTON_DOWN;
+ MouseEvent mouse_move(Event::ET_MOUSE_MOVED, event->x, event->y, flags);
root_view_->OnMouseMoved(mouse_move);
return true;
}
@@ -281,14 +338,13 @@ void WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) {
}
gboolean WidgetGtk::OnEnterNotify(GtkWidget* widget, GdkEventCrossing* event) {
- // TODO(port): We may not actually need this message; it looks like
- // OnNotificationNotify() takes care of this case...
return false;
}
gboolean WidgetGtk::OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) {
last_mouse_event_was_move_ = false;
- root_view_->ProcessOnMouseExited();
+ if (!has_capture_ && !is_mouse_down_)
+ root_view_->ProcessOnMouseExited();
return true;
}
@@ -302,6 +358,16 @@ gboolean WidgetGtk::OnKeyRelease(GtkWidget* widget, GdkEventKey* event) {
return root_view_->ProcessKeyEvent(key_event);
}
+gboolean WidgetGtk::OnGrabBrokeEvent(GtkWidget* widget, GdkEvent* event) {
+ HandleGrabBroke();
+ return false; // To let other widgets get the event.
+}
+
+void WidgetGtk::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) {
+ gtk_grab_remove(child_widget_parent_);
+ HandleGrabBroke();
+}
+
// static
WindowGtk* WidgetGtk::GetWindowForNative(GtkWidget* widget) {
gpointer user_data = g_object_get_data(G_OBJECT(widget), "chrome-window");
@@ -318,34 +384,27 @@ RootView* WidgetGtk::CreateRootView() {
}
bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) {
- last_mouse_event_was_move_ = false;
- // TODO: move this code into a common place. Also need support for
- // double/triple click.
- int flags = Event::GetFlagsFromGdkState(event->state);
- switch (event->button) {
- case 1:
- flags |= Event::EF_LEFT_BUTTON_DOWN;
- break;
- case 2:
- flags |= Event::EF_MIDDLE_BUTTON_DOWN;
- break;
- case 3:
- flags |= Event::EF_MIDDLE_BUTTON_DOWN;
- break;
- default:
- // We only deal with 1-3.
- break;
+ if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
+ // The sequence for double clicks is press, release, press, 2press, release.
+ // This means that at the time we get the second 'press' we don't know
+ // whether it corresponds to a double click or not. For now we're completely
+ // ignoring the 2press/3press events as they are duplicate. To make this
+ // work right we need to write our own code that detects if the press is a
+ // double/triple. For now we're completely punting, which means we always
+ // get single clicks.
+ // TODO: fix this.
+ return true;
}
- MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED,
- event->x, event->y, flags);
+
+ last_mouse_event_was_move_ = false;
+ MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, event->x, event->y,
+ GetFlagsForEventButton(*event));
if (root_view_->OnMousePressed(mouse_pressed)) {
is_mouse_down_ = true;
- // TODO(port): Enable this once I figure out what capture is.
- // if (!has_capture_) {
- // SetCapture();
- // has_capture_ = true;
- // current_action_ = FA_FORWARDING;
- // }
+ if (!has_capture_) {
+ has_capture_ = true;
+ gtk_grab_add(child_widget_parent_);
+ }
return true;
}
@@ -354,18 +413,15 @@ bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) {
void WidgetGtk::ProcessMouseReleased(GdkEventButton* event) {
last_mouse_event_was_move_ = false;
- MouseEvent mouse_up(Event::ET_MOUSE_RELEASED,
- event->x, event->y,
- Event::GetFlagsFromGdkState(event->state));
+ MouseEvent mouse_up(Event::ET_MOUSE_RELEASED, event->x, event->y,
+ GetFlagsForEventButton(*event));
// Release the capture first, that way we don't get confused if
// OnMouseReleased blocks.
- //
- // TODO(port): Enable this once I figure out what capture is.
- // if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
- // has_capture_ = false;
- // current_action_ = FA_NONE;
- // ReleaseCapture();
- // }
+
+ if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
+ has_capture_ = false;
+ gtk_grab_remove(child_widget_parent_);
+ }
is_mouse_down_ = false;
root_view_->OnMouseReleased(mouse_up, false);
}
@@ -497,17 +553,43 @@ gboolean WidgetGtk::CallVisibilityNotify(GtkWidget* widget,
return widget_gtk->OnVisibilityNotify(widget, event);
}
-// Returns the first ancestor of |widget| that is a window.
+// static
+gboolean WidgetGtk::CallGrabBrokeEvent(GtkWidget* widget, GdkEvent* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnGrabBrokeEvent(widget, event);
+}
+
+// static
+void WidgetGtk::CallGrabNotify(GtkWidget* widget, gboolean was_grabbed) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return;
+
+ return widget_gtk->OnGrabNotify(widget, was_grabbed);
+}
+
// static
Window* WidgetGtk::GetWindowImpl(GtkWidget* widget) {
GtkWidget* parent = widget;
while (parent) {
- WindowGtk* window = GetWindowForNative(widget);
- if (window)
- return window;
+ WidgetGtk* widget_gtk = GetViewForNative(parent);
+ if (widget_gtk && widget_gtk->is_window_)
+ return static_cast<WindowGtk*>(widget_gtk);
parent = gtk_widget_get_parent(parent);
}
return NULL;
}
+void WidgetGtk::HandleGrabBroke() {
+ if (has_capture_) {
+ if (is_mouse_down_)
+ root_view_->ProcessMouseDragCanceled();
+ is_mouse_down_ = false;
+ has_capture_ = false;
+ }
+}
+
} // namespace views
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
index a86a31b..cebc686 100644
--- a/views/widget/widget_gtk.h
+++ b/views/widget/widget_gtk.h
@@ -20,7 +20,7 @@ class View;
class WindowGtk;
// Widget implementation for GTK.
-class WidgetGtk : public Widget {
+class WidgetGtk : public Widget, public MessageLoopForUI::Observer {
public:
// Type of widget.
enum Type {
@@ -64,6 +64,10 @@ class WidgetGtk : public Widget {
virtual Window* GetWindow();
virtual const Window* GetWindow() const;
+ // MessageLoopForUI::Observer.
+ virtual void WillProcessEvent(GdkEvent* event) {}
+ virtual void DidProcessEvent(GdkEvent* event);
+
protected:
virtual void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation);
virtual void OnPaint(GtkWidget* widget, GdkEventExpose* event);
@@ -87,11 +91,20 @@ class WidgetGtk : public Widget {
GdkEventVisibility* event) {
return false;
}
+ virtual gboolean OnGrabBrokeEvent(GtkWidget* widget, GdkEvent* event);
+ virtual void OnGrabNotify(GtkWidget* widget, gboolean was_grabbed);
+
+ // Returns whether capture should be released on mouse release. The default
+ // is true.
+ virtual bool ReleaseCaptureOnMouseReleased() { return true; }
// Sets and retrieves the WidgetGtk in the userdata section of the widget.
static WindowGtk* GetWindowForNative(GtkWidget* widget);
static void SetWindowForNative(GtkWidget* widget, WindowGtk* window);
+ // Are we a subclass of WindowGtk?
+ bool is_window_;
+
private:
virtual RootView* CreateRootView();
@@ -121,12 +134,17 @@ class WidgetGtk : public Widget {
static gboolean CallScroll(GtkWidget* widget, GdkEventScroll* event);
static gboolean CallVisibilityNotify(GtkWidget* widget,
GdkEventVisibility* event);
+ static gboolean CallGrabBrokeEvent(GtkWidget* widget, GdkEvent* event);
+ static void CallGrabNotify(GtkWidget* widget, gboolean was_grabbed);
+ // Returns the first ancestor of |widget| that is a window.
static Window* GetWindowImpl(GtkWidget* widget);
// Creates the GtkWidget.
void CreateGtkWidget();
+ void HandleGrabBroke();
+
const Type type_;
// Our native views. If we're a window/popup, then widget_ is the window and
@@ -141,6 +159,9 @@ class WidgetGtk : public Widget {
// If true, the mouse is currently down.
bool is_mouse_down_;
+ // Have we done a mouse grab?
+ bool has_capture_;
+
// The following are used to detect duplicate mouse move events and not
// deliver them. Displaying a window may result in the system generating
// duplicate move events even though the mouse hasn't moved.
diff --git a/views/window/window_gtk.cc b/views/window/window_gtk.cc
index 06558ae..2a74706 100644
--- a/views/window/window_gtk.cc
+++ b/views/window/window_gtk.cc
@@ -176,6 +176,7 @@ WindowGtk::WindowGtk(WindowDelegate* window_delegate)
is_modal_(false),
window_delegate_(window_delegate),
non_client_view_(new NonClientView(this)) {
+ is_window_ = true;
window_delegate_->window_.reset(this);
}