diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 23:26:44 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 23:26:44 +0000 |
commit | faeaa946158d500de841248de8a0caab3d597309 (patch) | |
tree | 684918c2a0e34fe8f3c6cbbdf9ed2ab8ba8e0217 /views | |
parent | 2c0494456175ace10c2d83ddaab9aa4f5b0ed0cd (diff) | |
download | chromium_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.cc | 184 | ||||
-rw-r--r-- | views/widget/widget_gtk.h | 23 | ||||
-rw-r--r-- | views/window/window_gtk.cc | 1 |
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); } |