| Index: views/touchui/touch_event_dispatcher_gtk.cc
|
| diff --git a/views/touchui/touch_event_dispatcher_gtk.cc b/views/touchui/touch_event_dispatcher_gtk.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fc4fcd2e91a2c9945cf34b3b937f0d000972c4ce
|
| --- /dev/null
|
| +++ b/views/touchui/touch_event_dispatcher_gtk.cc
|
| @@ -0,0 +1,243 @@
|
| +// Copyright (c) 2010 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.
|
| +
|
| +// This file contains a function that receives a message from the message pump
|
| +// and dispatches that message to the appropriate root view. That function is
|
| +// 'DispatchEventForTouchUIGtk'. (Last function in this file.)
|
| +//
|
| +// The appropriate RootView is determined for each incoming event. The platform
|
| +// specific event is converted to a views event and dispatched directly to the
|
| +// appropriate RootView.
|
| +//
|
| +// This implementation is Gdk specific at the moment, but a future CL will
|
| +// provide a dispatcher that handles events from an X Windows message pump.
|
| +
|
| +// TODO(wyck): Make X Windows versions of all GdkEvent functions.
|
| +// (See individual TODO's below)
|
| +//
|
| +// When we switch the message pump from one that gives us GdkEvents to one that
|
| +// gives us X Windows events, we will need another version of each function.
|
| +// These ones are obviously specific to GdkEvent.
|
| +//
|
| +// Potential names:
|
| +// Maybe DispatchEventForTouchUIGtk will become DispatchEventForTouchUIX11.
|
| +//
|
| +// It may not be necessary to filter events with IsTouchEvent in the X version,
|
| +// because the message pump may pre-filter the message so that we get only
|
| +// touch events and there is nothing to filter out.
|
| +
|
| +#include <gdk/gdk.h>
|
| +#include <gdk/gdkx.h>
|
| +
|
| +#include "views/widget/root_view.h"
|
| +#include "views/widget/widget_gtk.h"
|
| +
|
| +namespace views {
|
| +
|
| +// gets the RootView associated with the GdkEvent.
|
| +//
|
| +// TODO(wyck): Make X Windows version of this function. (see earlier comment)
|
| +static RootView* FindRootViewForGdkEvent(GdkEvent* event) {
|
| + GdkEventAny* event_any = reinterpret_cast<GdkEventAny*>(event);
|
| + if (!event_any) {
|
| + DLOG(WARNING) << "FindRootViewForGdkEvent was passed a null GdkEvent";
|
| + return NULL;
|
| + }
|
| + GdkWindow* gdk_window = event_any->window;
|
| +
|
| + // and get the parent
|
| + gpointer data = NULL;
|
| + gdk_window_get_user_data(gdk_window, &data);
|
| + GtkWidget* gtk_widget = reinterpret_cast<GtkWidget*>(data);
|
| + if (!gtk_widget) {
|
| + DLOG(WARNING) << "no GtkWidget found for that GdkWindow";
|
| + return NULL;
|
| + }
|
| + WidgetGtk* widget_gtk = WidgetGtk::GetViewForNative(gtk_widget);
|
| +
|
| + if (!widget_gtk) {
|
| + DLOG(WARNING) << "no WidgetGtk found for that GtkWidget";
|
| + return NULL;
|
| + }
|
| + return widget_gtk->GetRootView();
|
| +}
|
| +
|
| +// Specialized dispatch for GDK_BUTTON_PRESS events
|
| +static void DispatchButtonPressGtk(const GdkEventButton& event,
|
| + RootView* root_view) {
|
| + // TODO(wyck): may need to remap coordinates:
|
| + // If so, it's like this:
|
| + // gdk_window_get_root_origin(dest, &dest_x, &dest_y);
|
| + // *x = event->x_root - dest_x;
|
| + // *y = event->y_root - dest_y;
|
| +
|
| + if (event.type == GDK_2BUTTON_PRESS || event.type == GDK_3BUTTON_PRESS) {
|
| + // TODO(wyck): decide what to do about 2 button and 3 button press msgs.
|
| + // You get both a GDK_BUTTON_PRESS and a GDK_2BUTTON_PRESS, so that's
|
| + // a bit weird.
|
| + // I'll ignore these events for now.
|
| + return;
|
| + }
|
| +
|
| + MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, event.x, event.y,
|
| + WidgetGtk::GetFlagsForEventButton(event));
|
| + root_view->OnMousePressed(mouse_pressed);
|
| +}
|
| +
|
| +// Specialized dispatch for GDK_BUTTON_RELEASE events
|
| +static void DispatchButtonReleaseGtk(const GdkEventButton& event,
|
| + RootView* root_view) {
|
| + // TODO(wyck): may need to remap coordinates.
|
| + // If so, it's like this:
|
| + // gdk_window_get_root_origin(dest, &dest_x, &dest_y);
|
| + // *x = event->x_root - dest_x;
|
| + // *y = event->y_root - dest_y;
|
| +
|
| + MouseEvent mouse_up(Event::ET_MOUSE_RELEASED, event.x, event.y,
|
| + WidgetGtk::GetFlagsForEventButton(event));
|
| +
|
| + root_view->OnMouseReleased(mouse_up, false);
|
| +}
|
| +
|
| +// Specialized dispatch for GDK_MOTION_NOTIFY events
|
| +static void DispatchMotionNotifyGtk(const GdkEventMotion& event,
|
| + RootView* root_view) {
|
| + // Regarding GDK_POINTER_MOTION_HINT_MASK:
|
| + // GDK_POINTER_MOTION_HINT_MASK may have been used to reduce the number of
|
| + // GDK_MOTION_NOTIFY events received. Normally a GDK_MOTION_NOTIFY event is
|
| + // received each time the mouse moves. But in the hint case, some events are
|
| + // marked with is_hint TRUE. Without further action after a hint, no more
|
| + // motion events will be received.
|
| + // To receive more motion events after a motion hint event, the application
|
| + // needs to ask for more by calling gdk_event_request_motions().
|
| + if (event.is_hint) {
|
| + gdk_event_request_motions(&event);
|
| + }
|
| +
|
| + // TODO(wyck): handle dragging
|
| + // Apparently it's our job to determine the difference between a move and a
|
| + // drag. We should dispatch OnMouseDragged with ET_MOUSE_DRAGGED instead.
|
| + // It's unclear what constitutes the dragging state. Which button(s)?
|
| + int flags = Event::GetFlagsFromGdkState(event.state);
|
| + MouseEvent mouse_move(Event::ET_MOUSE_MOVED, event.x, event.y, flags);
|
| + root_view->OnMouseMoved(mouse_move);
|
| +}
|
| +
|
| +// Specialized dispatch for GDK_ENTER_NOTIFY events
|
| +static void DispatchEnterNotifyGtk(const GdkEventCrossing& event,
|
| + RootView* root_view) {
|
| + // TODO(wyck): I'm not sure if this is necessary yet
|
| + int flags = (Event::GetFlagsFromGdkState(event.state) &
|
| + ~(Event::EF_LEFT_BUTTON_DOWN |
|
| + Event::EF_MIDDLE_BUTTON_DOWN |
|
| + Event::EF_RIGHT_BUTTON_DOWN));
|
| + MouseEvent mouse_move(Event::ET_MOUSE_MOVED, event.x, event.y, flags);
|
| + root_view->OnMouseMoved(mouse_move);
|
| +}
|
| +
|
| +// Specialized dispatch for GDK_LEAVE_NOTIFY events
|
| +static void DispatchLeaveNotifyGtk(const GdkEventCrossing& event,
|
| + RootView* root_view) {
|
| + // TODO(wyck): I'm not sure if this is necessary yet
|
| + root_view->ProcessOnMouseExited();
|
| +}
|
| +
|
| +// Dispatch an input-related GdkEvent to a RootView
|
| +static void DispatchEventToRootViewGtk(GdkEvent* event, RootView* root_view) {
|
| + if (!event) {
|
| + DLOG(WARNING) << "DispatchEventToRootView was passed a null GdkEvent";
|
| + return;
|
| + }
|
| + if (!root_view) {
|
| + DLOG(WARNING) << "DispatchEventToRootView was passed a null RootView";
|
| + return;
|
| + }
|
| + switch (event->type) {
|
| + case GDK_BUTTON_PRESS:
|
| + DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event),
|
| + root_view);
|
| + break;
|
| + case GDK_BUTTON_RELEASE:
|
| + DispatchButtonReleaseGtk(*reinterpret_cast<GdkEventButton*>(event),
|
| + root_view);
|
| + break;
|
| + case GDK_MOTION_NOTIFY:
|
| + DispatchMotionNotifyGtk(*reinterpret_cast<GdkEventMotion*>(event),
|
| + root_view);
|
| + break;
|
| + case GDK_ENTER_NOTIFY:
|
| + DispatchEnterNotifyGtk(*reinterpret_cast<GdkEventCrossing*>(event),
|
| + root_view);
|
| + break;
|
| + case GDK_LEAVE_NOTIFY:
|
| + DispatchLeaveNotifyGtk(*reinterpret_cast<GdkEventCrossing*>(event),
|
| + root_view);
|
| + break;
|
| + case GDK_2BUTTON_PRESS:
|
| + DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event),
|
| + root_view);
|
| + break;
|
| + case GDK_3BUTTON_PRESS:
|
| + DispatchButtonPressGtk(*reinterpret_cast<GdkEventButton*>(event),
|
| + root_view);
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +}
|
| +
|
| +// Called for input-related events only. Dispatches them directly to the
|
| +// associated RootView.
|
| +//
|
| +// TODO(wyck): Make X Windows version of this function. (see earlier comment)
|
| +static void HijackEventForTouchUIGtk(GdkEvent* event) {
|
| + // TODO(wyck): something like this...
|
| + RootView* root_view = FindRootViewForGdkEvent(event);
|
| + if (!root_view) {
|
| + DLOG(WARNING) << "no RootView found for that GdkEvent";
|
| + return;
|
| + }
|
| + DispatchEventToRootViewGtk(event, root_view);
|
| +}
|
| +
|
| +// returns true if the GdkEvent is a touch-related input event.
|
| +//
|
| +// TODO(wyck): Make X Windows version of this function. (see earlier comment)
|
| +//
|
| +// If the X Windows events are not-prefiltered, then we can provide a filtering
|
| +// function similar to this GdkEvent-specific function. Otherwise this function
|
| +// is not needed at all for the X Windows version.
|
| +static bool IsTouchEventGtk(GdkEvent* event) {
|
| + switch (event->type) {
|
| + case GDK_BUTTON_PRESS:
|
| + case GDK_BUTTON_RELEASE:
|
| + case GDK_MOTION_NOTIFY:
|
| + case GDK_ENTER_NOTIFY:
|
| + case GDK_LEAVE_NOTIFY:
|
| + case GDK_2BUTTON_PRESS:
|
| + case GDK_3BUTTON_PRESS:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +// This is the public entry point for the touch event dispatcher.
|
| +//
|
| +// Hijacks input-related events and routes them directly to a widget_gtk.
|
| +// Returns false for non-input-related events, in which case the caller is still
|
| +// responsible for dispatching the event.
|
| +//
|
| +// TODO(wyck): Make X Windows version of this function. (see earlier comment)
|
| +bool DispatchEventForTouchUIGtk(GdkEvent* event) {
|
| + // is this is an input-related event...
|
| + if (IsTouchEventGtk(event)) {
|
| + HijackEventForTouchUIGtk(event);
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| +}
|
| +} // namespace views
|
|
|