mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add multi-touch support for OSR (issue #1059)
This commit is contained in:
committed by
Marshall Greenblatt
parent
9ba28dd730
commit
5f615a95bc
@@ -15,6 +15,7 @@
|
||||
#define XK_3270 // for XK_3270_BackTab
|
||||
#include <X11/XF86keysym.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
@@ -28,6 +29,17 @@ namespace client {
|
||||
|
||||
namespace {
|
||||
|
||||
// Major opcode of XInputExtension, or -1 if XInput 2.2 is not available.
|
||||
int g_xinput_extension = -1;
|
||||
|
||||
// Static BrowserWindowOsrGtk::EventFilter needs to forward touch events
|
||||
// to correct browser, so we maintain a vector of all windows.
|
||||
std::vector<BrowserWindowOsrGtk*> g_browser_windows;
|
||||
|
||||
bool IsTouchAvailable() {
|
||||
return g_xinput_extension != -1;
|
||||
}
|
||||
|
||||
int GetCefStateModifiers(guint state) {
|
||||
int modifiers = 0;
|
||||
if (state & GDK_SHIFT_MASK)
|
||||
@@ -47,6 +59,20 @@ int GetCefStateModifiers(guint state) {
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
int GetCefStateModifiers(XIModifierState mods, XIButtonState buttons) {
|
||||
guint state = mods.effective;
|
||||
if (buttons.mask_len >= 1) {
|
||||
if (XIMaskIsSet(buttons.mask, 1))
|
||||
state |= GDK_BUTTON1_MASK;
|
||||
if (XIMaskIsSet(buttons.mask, 2))
|
||||
state |= GDK_BUTTON2_MASK;
|
||||
if (XIMaskIsSet(buttons.mask, 3))
|
||||
state |= GDK_BUTTON3_MASK;
|
||||
}
|
||||
|
||||
return GetCefStateModifiers(state);
|
||||
}
|
||||
|
||||
// From ui/events/keycodes/keyboard_codes_posix.h.
|
||||
enum KeyboardCode {
|
||||
VKEY_BACK = 0x08,
|
||||
@@ -948,9 +974,12 @@ BrowserWindowOsrGtk::BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
|
||||
drag_drop_(false),
|
||||
device_scale_factor_(1.0f) {
|
||||
client_handler_ = new ClientHandlerOsr(this, this, startup_url);
|
||||
g_browser_windows.push_back(this);
|
||||
}
|
||||
|
||||
BrowserWindowOsrGtk::~BrowserWindowOsrGtk() {
|
||||
g_browser_windows.erase(
|
||||
std::find(g_browser_windows.begin(), g_browser_windows.end(), this));
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
if (drag_trigger_event_) {
|
||||
@@ -1387,6 +1416,11 @@ void BrowserWindowOsrGtk::Create(ClientWindowHandle parent_handle) {
|
||||
|
||||
// Make the GlArea visible in the parent container.
|
||||
gtk_widget_show_all(parent_handle);
|
||||
|
||||
InitializeXinput(xdisplay_);
|
||||
|
||||
if (IsTouchAvailable())
|
||||
RegisterTouch();
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -1640,6 +1674,108 @@ gint BrowserWindowOsrGtk::FocusEvent(GtkWidget* widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void BrowserWindowOsrGtk::TouchEvent(CefXIDeviceEvent event) {
|
||||
if (!browser_.get())
|
||||
return;
|
||||
|
||||
XIDeviceEvent* ev = static_cast<XIDeviceEvent*>(event);
|
||||
CefTouchEvent cef_event;
|
||||
switch (ev->evtype) {
|
||||
case XI_TouchBegin:
|
||||
cef_event.type = CEF_TET_PRESSED;
|
||||
break;
|
||||
case XI_TouchUpdate:
|
||||
cef_event.type = CEF_TET_MOVED;
|
||||
break;
|
||||
case XI_TouchEnd:
|
||||
cef_event.type = CEF_TET_RELEASED;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
cef_event.id = ev->detail;
|
||||
cef_event.x = ev->event_x;
|
||||
cef_event.y = ev->event_y;
|
||||
cef_event.radius_x = 0;
|
||||
cef_event.radius_y = 0;
|
||||
cef_event.rotation_angle = 0;
|
||||
cef_event.pressure = 0;
|
||||
cef_event.modifiers = GetCefStateModifiers(ev->mods, ev->buttons);
|
||||
|
||||
browser_->GetHost()->SendTouchEvent(cef_event);
|
||||
}
|
||||
|
||||
void BrowserWindowOsrGtk::RegisterTouch() {
|
||||
GdkWindow* glwindow = gtk_widget_get_window(glarea_);
|
||||
::Window xwindow = GDK_WINDOW_XID(glwindow);
|
||||
uint32_t bitMask = XI_TouchBeginMask | XI_TouchUpdateMask | XI_TouchEndMask;
|
||||
|
||||
XIEventMask mask;
|
||||
mask.deviceid = XIAllMasterDevices;
|
||||
mask.mask = reinterpret_cast<unsigned char*>(&bitMask);
|
||||
mask.mask_len = sizeof(bitMask);
|
||||
XISelectEvents(xdisplay_, xwindow, &mask, 1);
|
||||
}
|
||||
|
||||
// static
|
||||
GdkFilterReturn BrowserWindowOsrGtk::EventFilter(GdkXEvent* gdk_xevent,
|
||||
GdkEvent* event,
|
||||
gpointer data) {
|
||||
XEvent* xevent = static_cast<XEvent*>(gdk_xevent);
|
||||
if (xevent->type == GenericEvent &&
|
||||
xevent->xgeneric.extension == g_xinput_extension) {
|
||||
XGetEventData(xevent->xcookie.display, &xevent->xcookie);
|
||||
XIDeviceEvent* ev = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
|
||||
|
||||
if (!ev)
|
||||
return GDK_FILTER_REMOVE;
|
||||
|
||||
for (BrowserWindowOsrGtk* browser_window : g_browser_windows) {
|
||||
GtkWidget* widget = browser_window->GetWindowHandle();
|
||||
::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(widget));
|
||||
if (xwindow == ev->event) {
|
||||
browser_window->TouchEvent(ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XFreeEventData(xevent->xcookie.display, &xevent->xcookie);
|
||||
// Even if we didn't find a consumer for this event, we will make sure Gdk
|
||||
// doesn't attempt to process the event, since it can't parse GenericEvents
|
||||
return GDK_FILTER_REMOVE;
|
||||
}
|
||||
|
||||
return GDK_FILTER_CONTINUE;
|
||||
}
|
||||
|
||||
// static
|
||||
void BrowserWindowOsrGtk::InitializeXinput(XDisplay* xdisplay) {
|
||||
static bool initialized = false;
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
int firstEvent, firstError;
|
||||
if (XQueryExtension(xdisplay, "XInputExtension", &g_xinput_extension,
|
||||
&firstEvent, &firstError)) {
|
||||
int major = 2, minor = 2;
|
||||
// X Input Extension 2.2 is needed for multitouch events.
|
||||
if (XIQueryVersion(xdisplay, &major, &minor) == Success) {
|
||||
// Ideally we would add an event filter for each glarea_ window
|
||||
// separately, but unfortunately GDK can't parse X GenericEvents
|
||||
// which have the target window stored in different way compared
|
||||
// to other X events. That is why we add this global event filter
|
||||
// just once, and dispatch the event to correct BrowserWindowOsrGtk
|
||||
// manually.
|
||||
gdk_window_add_filter(nullptr, &BrowserWindowOsrGtk::EventFilter,
|
||||
nullptr);
|
||||
} else {
|
||||
g_xinput_extension = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowserWindowOsrGtk::IsOverPopupWidget(int x, int y) const {
|
||||
const CefRect& rc = renderer_.popup_rect();
|
||||
int popup_right = rc.x + rc.width;
|
||||
|
Reference in New Issue
Block a user