diff options
25 files changed, 542 insertions, 286 deletions
diff --git a/app/app_base.gypi b/app/app_base.gypi index 2866bfd..2c04d38 100644 --- a/app/app_base.gypi +++ b/app/app_base.gypi @@ -153,6 +153,8 @@ 'keyboard_code_conversion_mac.h', 'keyboard_code_conversion_win.cc', 'keyboard_code_conversion_win.h', + 'keyboard_code_conversion_x.cc', + 'keyboard_code_conversion_x.h', 'keyboard_codes.h', 'keyboard_codes_win.h', 'keyboard_codes_posix.h', @@ -364,6 +366,8 @@ 'event_synthesis_gtk.h', 'keyboard_code_conversion_gtk.cc', 'keyboard_code_conversion_gtk.h', + 'keyboard_code_conversion_x.cc', + 'keyboard_code_conversion_x.h', 'keyboard_codes_win.h', ], }], @@ -386,6 +390,8 @@ 'keyboard_code_conversion_gtk.h', 'keyboard_code_conversion_mac.mm', 'keyboard_code_conversion_mac.h', + 'keyboard_code_conversion_x.cc', + 'keyboard_code_conversion_x.h', 'keyboard_codes_posix.h', ], }], diff --git a/app/keyboard_code_conversion_x.cc b/app/keyboard_code_conversion_x.cc new file mode 100644 index 0000000..679423b --- /dev/null +++ b/app/keyboard_code_conversion_x.cc @@ -0,0 +1,163 @@ +// 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 "app/keyboard_code_conversion_x.h" + +#include <X11/keysym.h> +#include <X11/Xlib.h> + +#include "base/logging.h" + +namespace app { + +// Get an app::KeyboardCode from an X keyevent +KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) { + KeySym keysym = XLookupKeysym(&xev->xkey, 0); + + // TODO(sad): Have |keysym| go through the X map list? + + switch (keysym) { + case XK_BackSpace: + return VKEY_BACK; + case XK_Tab: + return VKEY_TAB; + case XK_Linefeed: + case XK_Return: + return VKEY_RETURN; + case XK_Clear: + return VKEY_CLEAR; + case XK_KP_Space: + case XK_space: + return VKEY_SPACE; + case XK_Home: + case XK_KP_Home: + return VKEY_HOME; + case XK_End: + case XK_KP_End: + return VKEY_END; + case XK_Left: + case XK_KP_Left: + return VKEY_LEFT; + case XK_Right: + case XK_KP_Right: + return VKEY_RIGHT; + case XK_Down: + case XK_KP_Down: + return VKEY_DOWN; + case XK_Up: + case XK_KP_Up: + return VKEY_UP; + case XK_Control_L: + return VKEY_LCONTROL; + case XK_Control_R: + return VKEY_RCONTROL; + case XK_Escape: + return VKEY_ESCAPE; + case XK_A: + case XK_a: + return VKEY_A; + case XK_B: + case XK_b: + return VKEY_B; + case XK_C: + case XK_c: + return VKEY_C; + case XK_D: + case XK_d: + return VKEY_D; + case XK_E: + case XK_e: + return VKEY_E; + case XK_F: + case XK_f: + return VKEY_F; + case XK_G: + case XK_g: + return VKEY_G; + case XK_H: + case XK_h: + return VKEY_H; + case XK_I: + case XK_i: + return VKEY_I; + case XK_J: + case XK_j: + return VKEY_J; + case XK_K: + case XK_k: + return VKEY_K; + case XK_L: + case XK_l: + return VKEY_L; + case XK_M: + case XK_m: + return VKEY_M; + case XK_N: + case XK_n: + return VKEY_N; + case XK_O: + case XK_o: + return VKEY_O; + case XK_P: + case XK_p: + return VKEY_P; + case XK_Q: + case XK_q: + return VKEY_Q; + case XK_R: + case XK_r: + return VKEY_R; + case XK_S: + case XK_s: + return VKEY_S; + case XK_T: + case XK_t: + return VKEY_T; + case XK_U: + case XK_u: + return VKEY_U; + case XK_V: + case XK_v: + return VKEY_V; + case XK_W: + case XK_w: + return VKEY_W; + case XK_X: + case XK_x: + return VKEY_X; + case XK_Y: + case XK_y: + return VKEY_Y; + case XK_Z: + case XK_z: + return VKEY_Z; + case XK_0: + return VKEY_0; + case XK_1: + return VKEY_1; + case XK_2: + return VKEY_2; + case XK_3: + return VKEY_3; + case XK_4: + return VKEY_4; + case XK_5: + return VKEY_5; + case XK_6: + return VKEY_6; + case XK_7: + return VKEY_7; + case XK_8: + return VKEY_8; + case XK_9: + return VKEY_9; + + // TODO(sad): A lot of keycodes are still missing. + } + + DLOG(WARNING) << "Unknown keycode: " << keysym; + return VKEY_UNKNOWN; +} + +} // namespace app diff --git a/app/keyboard_code_conversion_x.h b/app/keyboard_code_conversion_x.h new file mode 100644 index 0000000..748ef86 --- /dev/null +++ b/app/keyboard_code_conversion_x.h @@ -0,0 +1,18 @@ +// 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. + +#ifndef APP_KEYBOARD_CODE_CONVERSION_X_H_ +#define APP_KEYBOARD_CODE_CONVERSION_X_H_ + +#include "app/keyboard_codes_posix.h" + +typedef union _XEvent XEvent; + +namespace app { + +KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev); + +} // namespace app + +#endif // APP_KEYBOARD_CODE_CONVERSION_X_H_ diff --git a/base/base.gypi b/base/base.gypi index 9a32325..690b852 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -456,6 +456,7 @@ 'message_pump_glib.h', 'message_pump_glib_x.cc', 'message_pump_glib_x.h', + 'message_pump_glib_x_dispatch.h', 'message_pump_libevent.cc', 'message_pump_libevent.h', 'message_pump_mac.h', diff --git a/base/message_loop.h b/base/message_loop.h index 37e4b81..f4b1a4d 100644 --- a/base/message_loop.h +++ b/base/message_loop.h @@ -26,6 +26,9 @@ #include "base/message_pump_glib.h" #endif #endif +#if defined(TOUCH_UI) +#include "base/message_pump_glib_x_dispatch.h" +#endif namespace base { class Histogram; @@ -290,7 +293,11 @@ class MessageLoop : public base::MessagePump::Delegate { typedef base::MessagePumpWin::Dispatcher Dispatcher; typedef base::MessagePumpForUI::Observer Observer; #elif !defined(OS_MACOSX) +#if defined(TOUCH_UI) + typedef base::MessagePumpGlibXDispatcher Dispatcher; +#else typedef base::MessagePumpForUI::Dispatcher Dispatcher; +#endif typedef base::MessagePumpForUI::Observer Observer; #endif diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc index ad6d177..616c24c 100644 --- a/base/message_pump_glib.cc +++ b/base/message_pump_glib.cc @@ -303,6 +303,10 @@ void MessagePumpForUI::RemoveObserver(Observer* observer) { observers_.RemoveObserver(observer); } +MessagePumpForUI::Dispatcher* MessagePumpForUI::GetDispatcher() { + return state_ ? state_->dispatcher : NULL; +} + void MessagePumpForUI::WillProcessEvent(GdkEvent* event) { FOR_EACH_OBSERVER(Observer, observers_, WillProcessEvent(event)); } diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h index 31d37c0..d8cbbda 100644 --- a/base/message_pump_glib.h +++ b/base/message_pump_glib.h @@ -88,6 +88,10 @@ class MessagePumpForUI : public MessagePump { // some task before/after calling the default handler (EventDispatcher). virtual void DispatchEvents(GdkEvent* event); + protected: + // Returns the dispatcher for the current run state (|state_->dispatcher|). + Dispatcher* GetDispatcher(); + private: // We may make recursive calls to Run, so we save state that needs to be // separate between them in this structure type. diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc index f77f61d..675774e 100644 --- a/base/message_pump_glib_x.cc +++ b/base/message_pump_glib_x.cc @@ -7,6 +7,8 @@ #include <gdk/gdkx.h> #include <X11/Xlib.h> +#include "base/message_pump_glib_x_dispatch.h" + namespace { gboolean PlaceholderDispatch(GSource* source, @@ -41,14 +43,16 @@ bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { if (capture_x_events_[xev.type]) { XNextEvent(display, &xev); - DLOG(INFO) << "nom noming event"; + bool processed = static_cast<MessagePumpGlibXDispatcher*> + (GetDispatcher())->Dispatch(&xev); - // TODO(sad): Create a GdkEvent from |xev| and pass it on to - // EventDispatcherX. The ultimate goal is to create a views::Event from - // |xev| and send it to a rootview. When done, the preceding DLOG will be - // removed. + if (!processed) { + DLOG(WARNING) << "Event (" << xev.type << ") not handled."; + } } else { - // TODO(sad): A couple of extra events can still sneak in during this + // TODO(sad): A couple of extra events can still sneak in during this. + // Those should be sent back to the X queue from the dispatcher + // EventDispatcherX. g_main_context_iteration(context, FALSE); } } @@ -81,6 +85,15 @@ void MessagePumpGlibX::InitializeEventsToCapture(void) { capture_x_events_[KeyRelease] = true; capture_gdk_events_[GDK_KEY_RELEASE] = true; + + capture_x_events_[ButtonPress] = true; + capture_gdk_events_[GDK_BUTTON_PRESS] = true; + + capture_x_events_[ButtonRelease] = true; + capture_gdk_events_[GDK_BUTTON_RELEASE] = true; + + capture_x_events_[MotionNotify] = true; + capture_gdk_events_[GDK_MOTION_NOTIFY] = true; } void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { @@ -94,7 +107,7 @@ void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { // TODO(sad): An X event is caught by the GDK handler. Put it back in the // X queue so that we catch it in the next iteration. When done, the // following DLOG statement will be removed. - DLOG(INFO) << "GDK ruined it!!"; + DLOG(WARNING) << "GDK received an event it shouldn't have"; } } diff --git a/base/message_pump_glib_x_dispatch.h b/base/message_pump_glib_x_dispatch.h new file mode 100644 index 0000000..95364a2 --- /dev/null +++ b/base/message_pump_glib_x_dispatch.h @@ -0,0 +1,28 @@ +// 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. + +#ifndef BASE_MESSAGE_PUMP_GLIB_X_DISPATCH_H +#define BASE_MESSAGE_PUMP_GLIB_X_DISPATCH_H + +#include "base/message_pump.h" +#include "base/message_pump_glib.h" + +typedef union _XEvent XEvent; + +namespace base { + +// The message pump used for TOUCH_UI on linux is MessagePumpGlibX, which can +// dispatch both GdkEvents* and XEvents* captured directly from X. +// MessagePumpForUI::Dispatcher provides the mechanism for dispatching +// GdkEvents. This class provides additional mechanism for dispatching XEvents. +class MessagePumpGlibXDispatcher : public MessagePumpForUI::Dispatcher { + public: + // Dispatches the event. If true is returned processing continues as + // normal. If false is returned, the nested loop exits immediately. + virtual bool Dispatch(XEvent* xevent) = 0; +}; + +} // namespace base + +#endif // BASE_MESSAGE_PUMP_GLIB_X_DISPATCH_H diff --git a/chrome/browser/chromeos/views/native_menu_domui.cc b/chrome/browser/chromeos/views/native_menu_domui.cc index d1a0458..5ce238c 100644 --- a/chrome/browser/chromeos/views/native_menu_domui.cc +++ b/chrome/browser/chromeos/views/native_menu_domui.cc @@ -22,6 +22,10 @@ #include "views/controls/menu/native_menu_gtk.h" #include "views/controls/menu/nested_dispatcher_gtk.h" +#if defined(TOUCH_UI) +#include "views/focus/accelerator_handler.h" +#endif + namespace { using chromeos::NativeMenuDOMUI; @@ -244,6 +248,12 @@ bool NativeMenuDOMUI::Dispatch(GdkEvent* event) { return true; } +#if defined(TOUCH_UI) +bool NativeMenuDOMUI::Dispatch(XEvent* xevent) { + return views::DispatchXEvent(xevent); +} +#endif + //////////////////////////////////////////////////////////////////////////////// // NativeMenuDOMUI, MenuControl implementation: diff --git a/chrome/browser/chromeos/views/native_menu_domui.h b/chrome/browser/chromeos/views/native_menu_domui.h index fb03604e..03a6b92 100644 --- a/chrome/browser/chromeos/views/native_menu_domui.h +++ b/chrome/browser/chromeos/views/native_menu_domui.h @@ -27,6 +27,10 @@ namespace views { class NestedDispatcherGtk; } // namespace views; +#if defined(TOUCH_UI) +typedef union _XEvent XEvent; +#endif + namespace chromeos { class MenuLocator; @@ -59,6 +63,9 @@ class NativeMenuDOMUI : public views::MenuWrapper, // Overriden from MessageLoopForUI::Dispatcher: virtual bool Dispatch(GdkEvent* event); +#if defined(TOUCH_UI) + virtual bool Dispatch(XEvent* xevent); +#endif // Overriden from DOMUIMenuControl; virtual menus::MenuModel* GetMenuModel() { return model_; } diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc index affddeb..e0701a2 100644 --- a/views/controls/menu/menu_controller.cc +++ b/views/controls/menu/menu_controller.cc @@ -25,6 +25,10 @@ #include "app/keyboard_code_conversion_gtk.h" #endif +#if defined(TOUCH_UI) +#include "views/focus/accelerator_handler.h" +#endif + using base::Time; using base::TimeDelta; @@ -848,12 +852,19 @@ bool MenuController::Dispatch(GdkEvent* event) { break; } - // We don not want Gtk to handle keyboard events, otherwise if they get + // We don't want Gtk to handle keyboard events, otherwise if they get // handled by Gtk, unexpected behavior may occur. For example Tab key // may cause unexpected focus traversing. gtk_main_do_event(event); return exit_type_ == EXIT_NONE; } + +#if defined(TOUCH_UI) +bool MenuController::Dispatch(XEvent* xev) { + return DispatchXEvent(xev); +} +#endif + #endif bool MenuController::OnKeyDown(int key_code diff --git a/views/controls/menu/menu_controller.h b/views/controls/menu/menu_controller.h index fe379b8..539c2ee 100644 --- a/views/controls/menu/menu_controller.h +++ b/views/controls/menu/menu_controller.h @@ -192,6 +192,10 @@ class MenuController : public MessageLoopForUI::Dispatcher { virtual bool Dispatch(GdkEvent* event); #endif +#if defined(TOUCH_UI) + virtual bool Dispatch(XEvent* xevent); +#endif + // Key processing. The return value of this is returned from Dispatch. // In other words, if this returns false (which happens if escape was // pressed, or a matching mnemonic was found) the message loop returns. diff --git a/views/controls/menu/native_menu_gtk.cc b/views/controls/menu/native_menu_gtk.cc index 12f73da..45c64c0 100644 --- a/views/controls/menu/native_menu_gtk.cc +++ b/views/controls/menu/native_menu_gtk.cc @@ -23,6 +23,10 @@ #include "views/controls/menu/menu_2.h" #include "views/controls/menu/nested_dispatcher_gtk.h" +#if defined(TOUCH_UI) +#include "views/focus/accelerator_handler.h" +#endif + namespace { const char kPositionString[] = "position"; @@ -220,6 +224,12 @@ void NativeMenuGtk::SetMinimumWidth(int width) { gtk_widget_set_size_request(menu_, width, -1); } +#if defined(TOUCH_UI) +bool NativeMenuGtk::Dispatch(XEvent* xevent) { + return DispatchXEvent(xevent); +} +#endif + bool NativeMenuGtk::Dispatch(GdkEvent* event) { if (menu_hidden_) { // The menu has been closed but the message loop is still nested. Don't diff --git a/views/controls/menu/native_menu_gtk.h b/views/controls/menu/native_menu_gtk.h index 6145925..4278d2c 100644 --- a/views/controls/menu/native_menu_gtk.h +++ b/views/controls/menu/native_menu_gtk.h @@ -51,6 +51,9 @@ class NativeMenuGtk : public MenuWrapper, // Overriden from MessageLoopForUI::Dispatcher: virtual bool Dispatch(GdkEvent* event); +#if defined(TOUCH_UI) + virtual bool Dispatch(XEvent* xevent); +#endif private: CHROMEGTK_CALLBACK_0(NativeMenuGtk, void, OnMenuHidden); diff --git a/views/controls/menu/nested_dispatcher_gtk.cc b/views/controls/menu/nested_dispatcher_gtk.cc index 856b0a8..ba7a7b2 100644 --- a/views/controls/menu/nested_dispatcher_gtk.cc +++ b/views/controls/menu/nested_dispatcher_gtk.cc @@ -4,6 +4,10 @@ #include "views/controls/menu/nested_dispatcher_gtk.h" +#if defined(TOUCH_UI) +#include "views/focus/accelerator_handler.h" +#endif + namespace views { NestedDispatcherGtk::NestedDispatcherGtk(MessageLoopForUI::Dispatcher* creator, @@ -30,10 +34,21 @@ void NestedDispatcherGtk::CreatorDestroyed() { bool NestedDispatcherGtk::Dispatch(GdkEvent* event) { if (creator_ != NULL) { +#if defined(TOUCH_UI) + return static_cast<base::MessagePumpForUI::Dispatcher*> + (creator_)->Dispatch(event); +#else return creator_->Dispatch(event); +#endif } else { return false; } } +#if defined(TOUCH_UI) +bool NestedDispatcherGtk::Dispatch(XEvent* xevent) { + return creator_ ? creator_->Dispatch(xevent) : false; +} +#endif + } // namespace views diff --git a/views/controls/menu/nested_dispatcher_gtk.h b/views/controls/menu/nested_dispatcher_gtk.h index 06f54fa..f17e9a4 100644 --- a/views/controls/menu/nested_dispatcher_gtk.h +++ b/views/controls/menu/nested_dispatcher_gtk.h @@ -3,11 +3,15 @@ // found in the LICENSE file. #ifndef VIEWS_CONTROLS_MENU_NESTED_DISPATCHER_GTK_H_ -#define VIEWS_CONTROLS_MENU_NATIVE_DISPATCHER_GTK_H_ +#define VIEWS_CONTROLS_MENU_NESTED_DISPATCHER_GTK_H_ #pragma once #include "base/message_loop.h" +#if defined(TOUCH_UI) +typedef union _XEvent XEvent; +#endif + namespace views { // A nested dispatcher that can out-live the creator of this @@ -36,6 +40,10 @@ class NestedDispatcherGtk : public MessageLoopForUI::Dispatcher { // Overriden from MessageLoopForUI::Dispatcher: virtual bool Dispatch(GdkEvent* event); +#if defined(TOUCH_UI) + virtual bool Dispatch(XEvent* xevent); +#endif + // Creator of the nested loop. MessageLoopForUI::Dispatcher* creator_; diff --git a/views/event.h b/views/event.h index f02bd1b..9da3945 100644 --- a/views/event.h +++ b/views/event.h @@ -13,6 +13,9 @@ #if defined(OS_LINUX) typedef struct _GdkEventKey GdkEventKey; #endif +#if defined(TOUCH_UI) +typedef union _XEvent XEvent; +#endif class OSExchangeData; @@ -222,6 +225,11 @@ class MouseEvent : public LocatedEvent { // from 'from' coordinate system to 'to' coordinate system MouseEvent(const MouseEvent& model, View* from, View* to); +#if defined(TOUCH_UI) + // Create a mouse event from an X mouse event. + explicit MouseEvent(XEvent* xevent); +#endif + // Conveniences to quickly test what button is down bool IsOnlyLeftMouseButton() const { return (GetFlags() & EF_LEFT_BUTTON_DOWN) && @@ -318,6 +326,11 @@ class KeyEvent : public Event { explicit KeyEvent(GdkEventKey* event); #endif +#if defined(TOUCH_UI) + // Create a key event from an X key event. + explicit KeyEvent(XEvent* xevent); +#endif + // This returns a VKEY_ value as defined in app/keyboard_codes.h which is // the Windows value. // On GTK, you can use the methods in keyboard_code_conversion_gtk.cc to diff --git a/views/event_x.cc b/views/event_x.cc new file mode 100644 index 0000000..69101bb --- /dev/null +++ b/views/event_x.cc @@ -0,0 +1,117 @@ +// 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 "views/event.h" + +#include <gdk/gdkx.h> + +#include "app/keyboard_code_conversion_x.h" +#include "views/widget/root_view.h" +#include "views/widget/widget_gtk.h" + +namespace views { + +namespace { + +int GetEventFlagsFromXState(unsigned int state) { + int flags = 0; + if (state & ControlMask) + flags |= Event::EF_CONTROL_DOWN; + if (state & ShiftMask) + flags |= Event::EF_SHIFT_DOWN; + if (state & Mod1Mask) + flags |= Event::EF_ALT_DOWN; + if (state & Button1Mask) + flags |= Event::EF_LEFT_BUTTON_DOWN; + if (state & Button2Mask) + flags |= Event::EF_MIDDLE_BUTTON_DOWN; + if (state & Button3Mask) + flags |= Event::EF_RIGHT_BUTTON_DOWN; + + return flags; +} + +// Get the event flag for the button in XButtonEvent. During a KeyPress event, +// |state| in XButtonEvent does not include the button that has just been +// pressed. Instead |state| contains flags for the buttons (if any) that had +// already been pressed before the current button, and |button| stores the most +// current pressed button. So, if you press down left mouse button, and while +// pressing it down, press down the right mouse button, then for the latter +// event, |state| would have Button1Mask set but not Button3Mask, and |button| +// would be 3. +int GetEventFlagsForButton(int button) { + switch (button) { + case 1: + return Event::EF_LEFT_BUTTON_DOWN; + case 2: + return Event::EF_MIDDLE_BUTTON_DOWN; + case 3: + return Event::EF_RIGHT_BUTTON_DOWN; + } + + DLOG(WARNING) << "Unexpected button (" << button << ") received."; + return 0; +} + +Event::EventType GetMouseEventType(XEvent* xev) { + switch (xev->type) { + case ButtonPress: + return Event::ET_MOUSE_PRESSED; + case ButtonRelease: + return Event::ET_MOUSE_RELEASED; + case MotionNotify: + if (xev->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) { + return Event::ET_MOUSE_DRAGGED; + } + return Event::ET_MOUSE_MOVED; + } + + return Event::ET_UNKNOWN; +} + +gfx::Point GetMouseEventLocation(XEvent* xev) { + switch (xev->type) { + case ButtonPress: + case ButtonRelease: + return gfx::Point(xev->xbutton.x, xev->xbutton.y); + + case MotionNotify: + return gfx::Point(xev->xmotion.x, xev->xmotion.y); + } + + return gfx::Point(); +} + +int GetMouseEventFlags(XEvent* xev) { + switch (xev->type) { + case ButtonPress: + case ButtonRelease: + return GetEventFlagsFromXState(xev->xbutton.state) | + GetEventFlagsForButton(xev->xbutton.button); + + case MotionNotify: + return GetEventFlagsFromXState(xev->xmotion.state); + } + + return 0; +} + +} // namespace + +KeyEvent::KeyEvent(XEvent* xev) + : Event(xev->type == KeyPress ? + Event::ET_KEY_PRESSED : Event::ET_KEY_RELEASED, + GetEventFlagsFromXState(xev->xkey.state)), + key_code_(app::KeyboardCodeFromXKeyEvent(xev)), + repeat_count_(0), + message_flags_(0) { +} + +MouseEvent::MouseEvent(XEvent* xev) + : LocatedEvent(GetMouseEventType(xev), + GetMouseEventLocation(xev), + GetMouseEventFlags(xev)) { +} + +} // namespace views diff --git a/views/focus/accelerator_handler.h b/views/focus/accelerator_handler.h index 3726d96..088f3f1 100644 --- a/views/focus/accelerator_handler.h +++ b/views/focus/accelerator_handler.h @@ -18,6 +18,12 @@ namespace views { +#if defined(TOUCH_UI) +// Dispatch an XEvent to the RootView. Return true if the event was dispatched +// and handled, false otherwise. +bool DispatchXEvent(XEvent* xevent); +#endif + // This class delegates the key messages to the associated FocusManager class // for the window that is receiving these messages for accelerator processing. class AcceleratorHandler : public MessageLoopForUI::Dispatcher { @@ -29,6 +35,9 @@ class AcceleratorHandler : public MessageLoopForUI::Dispatcher { virtual bool Dispatch(const MSG& msg); #else virtual bool Dispatch(GdkEvent* event); +#if defined(TOUCH_UI) + virtual bool Dispatch(XEvent* xev); +#endif #endif private: diff --git a/views/focus/accelerator_handler_gtk.cc b/views/focus/accelerator_handler_gtk.cc index a45aa83..f1dc140 100644 --- a/views/focus/accelerator_handler_gtk.cc +++ b/views/focus/accelerator_handler_gtk.cc @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "views/focus/accelerator_handler.h" + #include <gtk/gtk.h> #include "views/accelerator.h" -#include "views/focus/accelerator_handler.h" #include "views/focus/focus_manager.h" #include "views/widget/widget_gtk.h" diff --git a/views/focus/accelerator_handler_touch.cc b/views/focus/accelerator_handler_touch.cc index ddcdc04..9473600 100644 --- a/views/focus/accelerator_handler_touch.cc +++ b/views/focus/accelerator_handler_touch.cc @@ -2,31 +2,96 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "views/focus/accelerator_handler.h" + #include <gtk/gtk.h> +#include <X11/Xlib.h> #include "views/accelerator.h" -#include "views/focus/accelerator_handler.h" +#include "views/event.h" #include "views/focus/focus_manager.h" -#include "views/touchui/touch_event_dispatcher_gtk.h" +#include "views/widget/root_view.h" #include "views/widget/widget_gtk.h" namespace views { -AcceleratorHandler::AcceleratorHandler() {} +namespace { -bool AcceleratorHandler::Dispatch(GdkEvent* event) { - // The logic for handling keyboard accelerators has been moved into - // WidgetGtk::OnKeyEvent handler (views/widget/widget_gtk.cc). +RootView* FindRootViewForGdkWindow(GdkWindow* gdk_window) { + gpointer data = NULL; + gdk_window_get_user_data(gdk_window, &data); + GtkWidget* gtk_widget = reinterpret_cast<GtkWidget*>(data); + if (!gtk_widget || !GTK_IS_WIDGET(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(); +} + +} // namespace + +bool DispatchXEvent(XEvent* xev) { + GdkDisplay* gdisp = gdk_display_get_default(); + GdkWindow* gwind = gdk_window_lookup_for_display(gdisp, xev->xany.window); + + if (RootView* root = FindRootViewForGdkWindow(gwind)) { + switch (xev->type) { + case KeyPress: + case KeyRelease: { + KeyEvent keyev(xev); - // 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); + // If it's a keypress, check to see if it triggers an accelerator. + if (xev->type == KeyPress) { + FocusManager* focus_manager = root->GetFocusManager(); + if (focus_manager && !focus_manager->OnKeyEvent(keyev)) + return true; + } + return root->ProcessKeyEvent(keyev); + } + + case ButtonPress: + case ButtonRelease: { + MouseEvent mouseev(xev); + if (xev->type == ButtonPress) { + return root->OnMousePressed(mouseev); + } else { + root->OnMouseReleased(mouseev, false); + return true; // Assume the event has been processed to make sure we + // don't process it twice. + } + } + + case MotionNotify: { + MouseEvent mouseev(xev); + if (mouseev.GetType() == Event::ET_MOUSE_DRAGGED) { + return root->OnMouseDragged(mouseev); + } else { + root->OnMouseMoved(mouseev); + return true; + } + } + } + } + + return false; +} + +AcceleratorHandler::AcceleratorHandler() {} + +bool AcceleratorHandler::Dispatch(GdkEvent* event) { + gtk_main_do_event(event); return true; } +bool AcceleratorHandler::Dispatch(XEvent* xev) { + return DispatchXEvent(xev); +} + } // namespace views diff --git a/views/touchui/touch_event_dispatcher_gtk.cc b/views/touchui/touch_event_dispatcher_gtk.cc deleted file mode 100644 index fc4fcd2..0000000 --- a/views/touchui/touch_event_dispatcher_gtk.cc +++ /dev/null @@ -1,243 +0,0 @@ -// 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 deleted file mode 100644 index d80cb96..0000000 --- a/views/touchui/touch_event_dispatcher_gtk.h +++ /dev/null @@ -1,18 +0,0 @@ -// 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 e011383..c4878fe 100644 --- a/views/views.gyp +++ b/views/views.gyp @@ -32,6 +32,7 @@ ['include', '/win_[^/]*\\.cc$'], ]}], ['touchui==0', {'sources/': [ + ['exclude', 'event_x.cc$'], ['exclude', 'touchui/'], ['exclude', '_(touch)\\.cc$'], ]}], @@ -235,6 +236,7 @@ 'event.h', 'event_gtk.cc', 'event_win.cc', + 'event_x.cc', 'fill_layout.cc', 'fill_layout.h', 'focus/accelerator_handler.h', @@ -269,8 +271,6 @@ 'standard_layout.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', |