diff options
-rw-r--r-- | views/focus/accelerator_handler_touch.cc | 32 | ||||
-rw-r--r-- | views/touchui/touch_event_dispatcher_gtk.cc | 243 | ||||
-rw-r--r-- | views/touchui/touch_event_dispatcher_gtk.h | 18 | ||||
-rw-r--r-- | views/views.gyp | 9 | ||||
-rw-r--r-- | views/widget/widget_gtk.cc | 6 | ||||
-rw-r--r-- | views/widget/widget_gtk.h | 6 |
6 files changed, 307 insertions, 7 deletions
diff --git a/views/focus/accelerator_handler_touch.cc b/views/focus/accelerator_handler_touch.cc new file mode 100644 index 0000000..ddcdc04 --- /dev/null +++ b/views/focus/accelerator_handler_touch.cc @@ -0,0 +1,32 @@ +// 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. + +#include <gtk/gtk.h> + +#include "views/accelerator.h" +#include "views/focus/accelerator_handler.h" +#include "views/focus/focus_manager.h" +#include "views/touchui/touch_event_dispatcher_gtk.h" +#include "views/widget/widget_gtk.h" + +namespace views { + +AcceleratorHandler::AcceleratorHandler() {} + +bool AcceleratorHandler::Dispatch(GdkEvent* event) { + // The logic for handling keyboard accelerators has been moved into + // WidgetGtk::OnKeyEvent handler (views/widget/widget_gtk.cc). + + // TODO(wyck): Hijack TouchUI events at other calls to gtk_main_do_event. + // There are more places where we call gtk_main_do_event. + // In particular: the message pump itself, and the menu controller, + // as well as native_menu_gtk. + // This function contains the most important one important one, though. + if (!DispatchEventForTouchUIGtk(event)) + gtk_main_do_event(event); + + return true; +} + +} // namespace views diff --git a/views/touchui/touch_event_dispatcher_gtk.cc b/views/touchui/touch_event_dispatcher_gtk.cc new file mode 100644 index 0000000..fc4fcd2 --- /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 diff --git a/views/touchui/touch_event_dispatcher_gtk.h b/views/touchui/touch_event_dispatcher_gtk.h new file mode 100644 index 0000000..d80cb96 --- /dev/null +++ b/views/touchui/touch_event_dispatcher_gtk.h @@ -0,0 +1,18 @@ +// Copyright (c) 2006-2008 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. + +#ifndef VIEWS_TOUCHUI_TOUCH_EVENT_DISPATCHER_GTK_H_ +#define VIEWS_TOUCHUI_TOUCH_EVENT_DISPATCHER_GTK_H_ + +namespace views { + +// Dispatches a GdkEvent to the appropriate RootView. +// Returns true if the function dispatched (handled) the event. +// Returns false if the caller should dispatch the event. +// FYI: That would typically be done with gtk_main_do_event(event) +bool DispatchEventForTouchUIGtk(GdkEvent* gdk_event); + +} // namespace views + +#endif // VIEWS_TOUCHUI_TOUCH_EVENT_DISPATCHER_GTK_H_ diff --git a/views/views.gyp b/views/views.gyp index af6096d..077d842 100644 --- a/views/views.gyp +++ b/views/views.gyp @@ -33,6 +33,7 @@ ]}], ['touchui==0', {'sources/': [ ['exclude', 'touchui/'], + ['exclude', '_(touch)\\.cc$'], ]}], ], }, @@ -238,6 +239,7 @@ 'fill_layout.h', 'focus/accelerator_handler.h', 'focus/accelerator_handler_gtk.cc', + 'focus/accelerator_handler_touch.cc', 'focus/accelerator_handler_win.cc', 'focus/external_focus_tracker.cc', 'focus/external_focus_tracker.h', @@ -265,8 +267,10 @@ 'screen_gtk.cc', 'screen_win.cc', 'standard_layout.h', - 'touchui/gesture_manager.h', 'touchui/gesture_manager.cc', + 'touchui/gesture_manager.h', + 'touchui/touch_event_dispatcher_gtk.cc', + 'touchui/touch_event_dispatcher_gtk.h', 'view.cc', 'view.h', 'view_constants.cc', @@ -368,6 +372,9 @@ }], ['touchui==1', { 'defines': ['TOUCH_UI=1'], + 'sources/': [ + ['exclude', 'focus/accelerator_handler_gtk.cc'], + ], }], ['OS=="win"', { 'sources!': [ diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc index 3dfd8cc..badafec 100644 --- a/views/widget/widget_gtk.cc +++ b/views/widget/widget_gtk.cc @@ -908,9 +908,6 @@ bool WidgetGtk::HandleKeyboardEvent(GdkEventKey* event) { return handled; } -//////////////////////////////////////////////////////////////////////////////// -// WidgetGtk, protected: - // static int WidgetGtk::GetFlagsForEventButton(const GdkEventButton& event) { int flags = Event::GetFlagsFromGdkState(event.state); @@ -933,6 +930,9 @@ int WidgetGtk::GetFlagsForEventButton(const GdkEventButton& event) { return flags; } +//////////////////////////////////////////////////////////////////////////////// +// WidgetGtk, protected: + void WidgetGtk::OnSizeRequest(GtkWidget* widget, GtkRequisition* requisition) { // Do only return the preferred size for child windows. GtkWindow interprets // the requisition as a minimum size for top level windows, returning a diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h index 02d939d..4135c86 100644 --- a/views/widget/widget_gtk.h +++ b/views/widget/widget_gtk.h @@ -208,6 +208,9 @@ class WidgetGtk // Returns true if it's handled by the focus manager. bool HandleKeyboardEvent(GdkEventKey* event); + // Returns the view::Event::flags for a GdkEventButton. + static int GetFlagsForEventButton(const GdkEventButton& event); + protected: // If widget containes another widget, translates event coordinates to the // contained widget's coordinates, else returns original event coordinates. @@ -229,9 +232,6 @@ class WidgetGtk return false; } - // Returns the view::Event::flags for a GdkEventButton. - static int GetFlagsForEventButton(const GdkEventButton& event); - // Event handlers: CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnButtonPress, GdkEventButton*); CHROMEGTK_CALLBACK_1(WidgetGtk, void, OnSizeRequest, GtkRequisition*); |