diff --git a/cef3/cef.gyp b/cef3/cef.gyp index b70085b5a..6efd79c1f 100644 --- a/cef3/cef.gyp +++ b/cef3/cef.gyp @@ -209,7 +209,7 @@ }], [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { 'dependencies': [ - '<(DEPTH)/build/linux/system.gyp:gtk', + 'gtk', ], 'sources': [ '<@(includes_linux)', @@ -248,6 +248,7 @@ 'tests/cefclient/client_app.h', 'tests/cefclient/client_switches.cpp', 'tests/cefclient/client_switches.h', + 'tests/cefclient/res/osr_test.html', 'tests/unittests/command_line_unittest.cc', 'tests/unittests/cookie_unittest.cc', 'tests/unittests/dialog_unittest.cc', @@ -258,6 +259,7 @@ 'tests/unittests/jsdialog_unittest.cc', 'tests/unittests/life_span_unittest.cc', 'tests/unittests/navigation_unittest.cc', + 'tests/unittests/os_rendering_unittest.cc', 'tests/unittests/process_message_unittest.cc', 'tests/unittests/request_unittest.cc', 'tests/cefclient/resource_util.h', @@ -311,9 +313,7 @@ [ 'OS=="win"', { 'sources': [ 'tests/cefclient/cefclient.rc', - 'tests/cefclient/res/osr_test.html', 'tests/cefclient/resource_util_win.cpp', - 'tests/unittests/os_rendering_unittest.cc', ], }], [ 'OS=="mac"', { @@ -422,7 +422,6 @@ 'sources': [ 'tests/cefclient/resource_util_mac.mm', 'tests/cefclient/resource_util_posix.cpp', - 'tests/unittests/os_rendering_unittest.cc', 'tests/unittests/os_rendering_unittest_mac.h', 'tests/unittests/os_rendering_unittest_mac.mm', 'tests/unittests/run_all_unittests_mac.mm', @@ -432,6 +431,18 @@ 'dependencies': [ '<(DEPTH)/build/linux/system.gyp:gtk', ], + 'sources': [ + 'tests/cefclient/resource_util_linux.cpp', + 'tests/cefclient/resource_util_posix.cpp', + ], + 'copies': [ + { + 'destination': '<(PRODUCT_DIR)/files', + 'files': [ + 'tests/cefclient/res/osr_test.html', + ], + }, + ], }], ], }, @@ -821,6 +832,8 @@ ], 'sources': [ '<@(includes_common)', + 'libcef/browser/backing_store_osr.cc', + 'libcef/browser/backing_store_osr.h', 'libcef/browser/browser_context.cc', 'libcef/browser/browser_context.h', 'libcef/browser/browser_host_impl.cc', @@ -878,6 +891,8 @@ 'libcef/browser/path_util_impl.cc', 'libcef/browser/process_util_impl.cc', 'libcef/browser/proxy_stubs.cc', + 'libcef/browser/render_widget_host_view_osr.cc', + 'libcef/browser/render_widget_host_view_osr.h', 'libcef/browser/resource_dispatcher_host_delegate.cc', 'libcef/browser/resource_dispatcher_host_delegate.h', 'libcef/browser/resource_request_job.cc', @@ -904,6 +919,8 @@ 'libcef/browser/url_request_context_proxy.h', 'libcef/browser/url_request_interceptor.cc', 'libcef/browser/url_request_interceptor.h', + 'libcef/browser/web_contents_view_osr.cc', + 'libcef/browser/web_contents_view_osr.h', 'libcef/browser/web_plugin_impl.cc', 'libcef/browser/web_plugin_impl.h', 'libcef/browser/xml_reader_impl.cc', @@ -1011,17 +1028,11 @@ ['OS=="win"', { 'sources': [ '<@(includes_win)', - 'libcef/browser/backing_store_osr.cc', - 'libcef/browser/backing_store_osr.h', 'libcef/browser/browser_host_impl_win.cc', 'libcef/browser/browser_main_win.cc', 'libcef/browser/javascript_dialog_win.cc', 'libcef/browser/menu_creator_runner_win.cc', 'libcef/browser/menu_creator_runner_win.h', - 'libcef/browser/render_widget_host_view_osr.cc', - 'libcef/browser/render_widget_host_view_osr.h', - 'libcef/browser/web_contents_view_osr.cc', - 'libcef/browser/web_contents_view_osr.h', # Include sources for context menu implementation. '<(DEPTH)/ui/views/controls/menu/menu_2.cc', '<(DEPTH)/ui/views/controls/menu/menu_2.h', @@ -1039,20 +1050,14 @@ '<@(includes_mac)', 'libcef/browser/application_mac.h', 'libcef/browser/application_mac.mm', - 'libcef/browser/backing_store_osr.cc', - 'libcef/browser/backing_store_osr.h', 'libcef/browser/browser_host_impl_mac.mm', 'libcef/browser/browser_main_mac.mm', 'libcef/browser/javascript_dialog_mac.mm', 'libcef/browser/menu_creator_runner_mac.h', 'libcef/browser/menu_creator_runner_mac.mm', 'libcef/browser/render_widget_host_view_osr_mac.mm', - 'libcef/browser/render_widget_host_view_osr.cc', - 'libcef/browser/render_widget_host_view_osr.h', 'libcef/browser/text_input_client_osr_mac.mm', 'libcef/browser/text_input_client_osr_mac.h', - 'libcef/browser/web_contents_view_osr.cc', - 'libcef/browser/web_contents_view_osr.h', # Include sources for context menu implementation. '<(DEPTH)/chrome/browser/ui/cocoa/event_utils.mm', '<(DEPTH)/chrome/browser/ui/cocoa/event_utils.h', @@ -1337,5 +1342,32 @@ }, # target cef_unittests_helper_app ], }], # OS=="mac" + [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + 'targets': [ + { + 'target_name': 'gtk', + 'type': 'none', + 'variables': { + # gtk requires gmodule, but it does not list it as a dependency + # in some misconfigured systems. + # gtkglext is required by the cefclient OSR example. + 'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0 gtkglext-1.0', + }, + 'direct_dependent_settings': { + 'cflags': [ + 'widget = src->widget; target->parent_widget = src->parent_widget; + target->window_rendering_disabled = src->window_rendering_disabled; + target->transparent_painting = src->transparent_painting; + target->widget = src->widget; } }; @@ -126,6 +128,15 @@ class CefWindowInfo : public CefStructBase { void SetAsChild(CefWindowHandle ParentWidget) { parent_widget = ParentWidget; } + + void SetTransparentPainting(bool transparentPainting) { + transparent_painting = transparentPainting; + } + + void SetAsOffScreen(CefWindowHandle ParentWidget) { + window_rendering_disabled = true; + parent_widget = ParentWidget; + } }; #endif // OS_LINUX diff --git a/cef3/include/internal/cef_types_linux.h b/cef3/include/internal/cef_types_linux.h index db30527b6..336517331 100644 --- a/cef3/include/internal/cef_types_linux.h +++ b/cef3/include/internal/cef_types_linux.h @@ -43,7 +43,7 @@ extern "C" { #endif // Handle types. -#define cef_cursor_handle_t void* +#define cef_cursor_handle_t GdkCursor* #define cef_event_handle_t GdkEvent* #define cef_window_handle_t GtkWidget* #define cef_text_input_context_t void* @@ -63,6 +63,14 @@ typedef struct _cef_window_info_t { // Pointer for the parent GtkBox widget. cef_window_handle_t parent_widget; + // If window rendering is disabled no browser window will be created. Set + // |parent_widget| to the window that will act as the parent for popup menus, + // dialog boxes, etc. + bool window_rendering_disabled; + + // Set to true to enable transparent painting. + bool transparent_painting; + // Pointer for the new browser widget. cef_window_handle_t widget; } cef_window_info_t; diff --git a/cef3/libcef/browser/browser_host_impl.cc b/cef3/libcef/browser/browser_host_impl.cc index 34423118a..19f1080a4 100644 --- a/cef3/libcef/browser/browser_host_impl.cc +++ b/cef3/libcef/browser/browser_host_impl.cc @@ -17,10 +17,12 @@ #include "libcef/browser/devtools_delegate.h" #include "libcef/browser/media_capture_devices_dispatcher.h" #include "libcef/browser/navigate_params.h" +#include "libcef/browser/render_widget_host_view_osr.h" #include "libcef/browser/scheme_registration.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/url_request_context_getter.h" #include "libcef/browser/url_request_context_getter_proxy.h" +#include "libcef/browser/web_contents_view_osr.h" #include "libcef/common/cef_messages.h" #include "libcef/common/cef_switches.h" #include "libcef/common/drag_data_impl.h" @@ -48,11 +50,6 @@ #include "content/public/common/file_chooser_params.h" #include "ui/shell_dialogs/selected_file_info.h" -#if defined(OS_WIN) || defined(OS_MACOSX) -#include "libcef/browser/render_widget_host_view_osr.h" -#include "libcef/browser/web_contents_view_osr.h" -#endif - namespace { class CreateBrowserHelper { @@ -348,9 +345,6 @@ CefRefPtr CefBrowserHostImpl::Create( return NULL; } - // TODO(port): Implement this method to work on other platforms as part of - // off-screen rendering support. -#if defined(OS_WIN) || defined(OS_MACOSX) if (browser->IsWindowRenderingDisabled()) { CefRenderWidgetHostViewOSR* view = static_cast( @@ -358,7 +352,6 @@ CefRefPtr CefBrowserHostImpl::Create( if (view) view->set_browser_impl(browser); } -#endif // defined(OS_WIN) || defined(OS_MACOSX) if (client.get()) { CefRefPtr handler = client->GetLifeSpanHandler(); @@ -691,16 +684,10 @@ void CefBrowserHostImpl::NotifyScreenInfoChanged() { if (!view) return; -#if defined(OS_WIN) || defined(OS_MACOSX) CefRenderWidgetHostViewOSR* orview = static_cast(view); orview->OnScreenInfoChanged(); -#else - // TODO(port): Implement this method to work on other platforms as part of - // off-screen rendering support. - NOTREACHED(); -#endif } void CefBrowserHostImpl::Invalidate(const CefRect& dirtyRect, @@ -719,7 +706,6 @@ void CefBrowserHostImpl::Invalidate(const CefRect& dirtyRect, if (!web_contents()) return; -#if defined(OS_WIN) || defined(OS_MACOSX) content::RenderWidgetHostView* view = web_contents()->GetRenderViewHost()->GetView(); CefRenderWidgetHostViewOSR* orview = @@ -730,11 +716,6 @@ void CefBrowserHostImpl::Invalidate(const CefRect& dirtyRect, dirtyRect.width, dirtyRect.height); orview->Invalidate(rect, type); } -#else - // TODO(port): Implement this method to work on other platforms as part of - // off-screen rendering support. - NOTREACHED(); -#endif } void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) { @@ -752,7 +733,6 @@ void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) { if (widget) widget->ForwardKeyboardEvent(web_event); } else { -#if defined(OS_WIN) || defined(OS_MACOSX) if (!web_contents()) return; content::RenderWidgetHostView* view = @@ -761,11 +741,6 @@ void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) { static_cast(view); if (orview) orview->SendKeyEvent(web_event); -#else - // TODO(port): Implement this method to work on other platforms as part of - // off-screen rendering support. - NOTREACHED(); -#endif } } @@ -816,7 +791,6 @@ void CefBrowserHostImpl::SendMouseWheelEvent(const CefMouseEvent& event, if (widget) widget->ForwardWheelEvent(web_event); } else { -#if defined(OS_WIN) || defined(OS_MACOSX) if (!web_contents()) return; content::RenderWidgetHostView* view = @@ -826,11 +800,6 @@ void CefBrowserHostImpl::SendMouseWheelEvent(const CefMouseEvent& event, if (orview) orview->SendMouseWheelEvent(web_event); -#else - // TODO(port): Implement this method to work on other platforms as part of - // off-screen rendering support. - NOTREACHED(); -#endif } } @@ -870,7 +839,6 @@ void CefBrowserHostImpl::SendMouseEvent(const WebKit::WebMouseEvent& event) { if (widget) widget->ForwardMouseEvent(event); } else { -#if defined(OS_WIN) || defined(OS_MACOSX) if (!web_contents()) return; content::RenderWidgetHostView* view = @@ -880,11 +848,6 @@ void CefBrowserHostImpl::SendMouseEvent(const WebKit::WebMouseEvent& event) { if (orview) orview->SendMouseEvent(event); -#else - // TODO(port): Implement this method to work on other platforms as part of - // off-screen rendering support. - NOTREACHED(); -#endif } } diff --git a/cef3/libcef/browser/browser_host_impl_gtk.cc b/cef3/libcef/browser/browser_host_impl_gtk.cc index 2a7bf96b1..902fe02ff 100644 --- a/cef3/libcef/browser/browser_host_impl_gtk.cc +++ b/cef3/libcef/browser/browser_host_impl_gtk.cc @@ -6,17 +6,21 @@ #include "libcef/browser/browser_host_impl.h" #include +#include #include "libcef/browser/thread_util.h" #include "base/bind.h" #include "base/utf_string_conversions.h" +#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/web_contents_view.h" #include "content/public/common/file_chooser_params.h" #include "content/public/common/renderer_preferences.h" #include "grit/cef_strings.h" #include "grit/ui_strings.h" #include "net/base/mime_util.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.h" #include "ui/base/l10n/l10n_util.h" namespace { @@ -231,6 +235,14 @@ bool RunFileDialog(const content::FileChooserParams& params, return success; } +// Returns the number of seconds since system boot. +long GetSystemUptime() { + struct sysinfo info; + if (sysinfo(&info) == 0) + return info.uptime; + return 0; +} + } // namespace bool CefBrowserHostImpl::PlatformCreateWindow() { @@ -308,7 +320,9 @@ void CefBrowserHostImpl::PlatformSizeTo(int width, int height) { } CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() { - return window_info_.widget; + return IsWindowRenderingDisabled() ? + window_info_.parent_widget : + window_info_.widget; } bool CefBrowserHostImpl::PlatformViewText(const std::string& text) { @@ -371,49 +385,190 @@ void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) { // static bool CefBrowserHostImpl::IsWindowRenderingDisabled(const CefWindowInfo& info) { - // TODO(port): Implement this method as part of off-screen rendering support. - return false; + return info.window_rendering_disabled ? true : false; } bool CefBrowserHostImpl::IsTransparent() { - return false; + return window_info_.transparent_painting != 0; } void CefBrowserHostImpl::PlatformTranslateKeyEvent( - content::NativeWebKeyboardEvent& native_event, - const CefKeyEvent& event) { - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); + content::NativeWebKeyboardEvent& result, + const CefKeyEvent& key_event) { + // Use a synthetic GdkEventKey in order to obtain the windowsKeyCode member + // from the NativeWebKeyboardEvent constructor. This is the only member + // which cannot be easily translated (without hardcoding keyCodes). + + guint state = 0; + if (key_event.modifiers & EVENTFLAG_SHIFT_DOWN) + state |= GDK_SHIFT_MASK; + if (key_event.modifiers & EVENTFLAG_CAPS_LOCK_ON) + state |= GDK_LOCK_MASK; + if (key_event.modifiers & EVENTFLAG_CONTROL_DOWN) + state |= GDK_CONTROL_MASK; + if (key_event.modifiers & EVENTFLAG_ALT_DOWN) + state |= GDK_MOD1_MASK; + if (key_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) + state |= GDK_BUTTON1_MASK; + if (key_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) + state |= GDK_BUTTON2_MASK; + if (key_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) + state |= GDK_BUTTON3_MASK; + + GdkKeymap* keymap = gdk_keymap_get_for_display(gdk_display_get_default()); + + GdkKeymapKey *keys = NULL; + gint n_keys = 0; + if (gdk_keymap_get_entries_for_keyval(keymap, key_event.native_key_code, + &keys, &n_keys)) { + GdkEventKey event; + event.type = GDK_KEY_PRESS; + event.window = NULL; + event.send_event = 0; + event.time = 0; + event.state = state; + event.keyval = key_event.native_key_code; + event.length = 0; + event.string = NULL; + event.hardware_keycode = keys[0].keycode; + event.group = keys[0].group; + event.is_modifier = 0; + g_free(keys); + result = content::NativeWebKeyboardEvent( + reinterpret_cast(&event)); + } + + result.timeStampSeconds = GetSystemUptime(); + + switch (key_event.type) { + case KEYEVENT_RAWKEYDOWN: + case KEYEVENT_KEYDOWN: + result.type = WebKit::WebInputEvent::RawKeyDown; + break; + case KEYEVENT_KEYUP: + result.type = WebKit::WebInputEvent::KeyUp; + break; + case KEYEVENT_CHAR: + result.type = WebKit::WebInputEvent::Char; + break; + default: + NOTREACHED(); + } } void CefBrowserHostImpl::PlatformTranslateClickEvent( - WebKit::WebMouseEvent& ev, + WebKit::WebMouseEvent& result, const CefMouseEvent& mouse_event, MouseButtonType type, bool mouseUp, int clickCount) { - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); + PlatformTranslateMouseEvent(result, mouse_event); + + switch (type) { + case MBT_LEFT: + result.type = mouseUp ? WebKit::WebInputEvent::MouseUp : + WebKit::WebInputEvent::MouseDown; + result.button = WebKit::WebMouseEvent::ButtonLeft; + break; + case MBT_MIDDLE: + result.type = mouseUp ? WebKit::WebInputEvent::MouseUp : + WebKit::WebInputEvent::MouseDown; + result.button = WebKit::WebMouseEvent::ButtonMiddle; + break; + case MBT_RIGHT: + result.type = mouseUp ? WebKit::WebInputEvent::MouseUp : + WebKit::WebInputEvent::MouseDown; + result.button = WebKit::WebMouseEvent::ButtonRight; + break; + default: + NOTREACHED(); + } + + result.clickCount = clickCount; } void CefBrowserHostImpl::PlatformTranslateMoveEvent( - WebKit::WebMouseEvent& ev, + WebKit::WebMouseEvent& result, const CefMouseEvent& mouse_event, bool mouseLeave) { - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); + PlatformTranslateMouseEvent(result, mouse_event); + + if (!mouseLeave) { + result.type = WebKit::WebInputEvent::MouseMove; + if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) + result.button = WebKit::WebMouseEvent::ButtonLeft; + else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) + result.button = WebKit::WebMouseEvent::ButtonMiddle; + else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) + result.button = WebKit::WebMouseEvent::ButtonRight; + else + result.button = WebKit::WebMouseEvent::ButtonNone; + } else { + result.type = WebKit::WebInputEvent::MouseLeave; + result.button = WebKit::WebMouseEvent::ButtonNone; + } + + result.clickCount = 0; } void CefBrowserHostImpl::PlatformTranslateWheelEvent( - WebKit::WebMouseWheelEvent& ev, + WebKit::WebMouseWheelEvent& result, const CefMouseEvent& mouse_event, int deltaX, int deltaY) { - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); + result = WebKit::WebMouseWheelEvent(); + PlatformTranslateMouseEvent(result, mouse_event); + + result.type = WebKit::WebInputEvent::MouseWheel; + + static const double scrollbarPixelsPerGtkTick = 40.0; + result.deltaX = deltaX; + result.deltaY = deltaY; + result.wheelTicksX = result.deltaX / scrollbarPixelsPerGtkTick; + result.wheelTicksY = result.deltaY / scrollbarPixelsPerGtkTick; + result.hasPreciseScrollingDeltas = true; + + // Unless the phase and momentumPhase are passed in as parameters to this + // function, there is no way to know them + result.phase = WebKit::WebMouseWheelEvent::PhaseNone; + result.momentumPhase = WebKit::WebMouseWheelEvent::PhaseNone; + + if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) + result.button = WebKit::WebMouseEvent::ButtonLeft; + else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) + result.button = WebKit::WebMouseEvent::ButtonMiddle; + else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) + result.button = WebKit::WebMouseEvent::ButtonRight; + else + result.button = WebKit::WebMouseEvent::ButtonNone; } void CefBrowserHostImpl::PlatformTranslateMouseEvent( - WebKit::WebMouseEvent& ev, + WebKit::WebMouseEvent& result, const CefMouseEvent& mouse_event) { - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); + // position + result.x = mouse_event.x; + result.y = mouse_event.y; + result.windowX = result.x; + result.windowY = result.y; + result.globalX = result.x; + result.globalY = result.y; + + // global position + if (IsWindowRenderingDisabled()) { + GetClient()->GetRenderHandler()->GetScreenPoint(GetBrowser(), + result.x, result.y, + result.globalX, result.globalY); + } else { + GtkWidget* window = gtk_widget_get_toplevel(GetWindowHandle()); + GdkWindow* gdk_window = gtk_widget_get_window(window); + gint xorigin, yorigin; + gdk_window_get_root_origin(gdk_window, &xorigin, &yorigin); + result.globalX = xorigin + result.x; + result.globalY = yorigin + result.y; + } + + // modifiers + result.modifiers |= TranslateModifiers(mouse_event.modifiers); + + // timestamp + result.timeStampSeconds = GetSystemUptime(); } diff --git a/cef3/libcef/browser/content_browser_client.cc b/cef3/libcef/browser/content_browser_client.cc index 108541390..53bfe05b0 100644 --- a/cef3/libcef/browser/content_browser_client.cc +++ b/cef3/libcef/browser/content_browser_client.cc @@ -18,6 +18,7 @@ #include "libcef/browser/resource_dispatcher_host_delegate.h" #include "libcef/browser/speech_recognition_manager_delegate.h" #include "libcef/browser/thread_util.h" +#include "libcef/browser/web_contents_view_osr.h" #include "libcef/browser/web_plugin_impl.h" #include "libcef/common/cef_switches.h" #include "libcef/common/command_line_impl.h" @@ -37,10 +38,6 @@ #include "googleurl/src/gurl.h" #include "ui/base/ui_base_switches.h" -#if defined(OS_WIN) || defined(OS_MACOSX) -#include "libcef/browser/web_contents_view_osr.h" -#endif - namespace { // In-memory store for access tokens used by geolocation. @@ -373,9 +370,7 @@ CefContentBrowserClient::OverrideCreateWebContentsView( content::RenderViewHostDelegateView** render_view_host_delegate_view) { content::WebContentsViewPort* view = NULL; *render_view_host_delegate_view = NULL; - // TODO(port): Implement this method to work on other platforms as part of - // off-screen rendering support. -#if defined(OS_WIN) || defined(OS_MACOSX) + CefBrowserContext* browserContext = static_cast(web_contents->GetBrowserContext()); @@ -385,7 +380,6 @@ CefContentBrowserClient::OverrideCreateWebContentsView( *render_view_host_delegate_view = view_or; view = view_or; } -#endif // defined(OS_WIN) || defined(OS_MACOSX) return view; } diff --git a/cef3/libcef/browser/menu_creator_runner_gtk.cc b/cef3/libcef/browser/menu_creator_runner_gtk.cc index c2f5fe1ca..be06e52b7 100644 --- a/cef3/libcef/browser/menu_creator_runner_gtk.cc +++ b/cef3/libcef/browser/menu_creator_runner_gtk.cc @@ -22,25 +22,53 @@ class CefMenuDelegate : public MenuGtk::Delegate { CefMenuCreatorRunnerGtk::CefMenuCreatorRunnerGtk() { } +CefMenuCreatorRunnerGtk::~CefMenuCreatorRunnerGtk() { + if (menu_.get()) + menu_->Cancel(); +} + bool CefMenuCreatorRunnerGtk::RunContextMenu(CefMenuCreator* manager) { + gfx::Point screen_point; + GdkEventButton* event = NULL; + + if (manager->browser()->IsWindowRenderingDisabled()) { + CefRefPtr client = manager->browser()->GetClient(); + if (!client.get()) + return false; + + CefRefPtr handler = client->GetRenderHandler(); + if (!handler.get()) + return false; + + int screenX = 0, screenY = 0; + if (!handler->GetScreenPoint(manager->browser(), + manager->params().x, manager->params().y, + screenX, screenY)) { + return false; + } + + screen_point = gfx::Point(screenX, screenY); + } else { + gfx::Rect bounds; + manager->browser()->GetWebContents()->GetView()->GetContainerBounds(&bounds); + screen_point = bounds.origin(); + screen_point.Offset(manager->params().x, manager->params().y); + + content::RenderWidgetHostView* view = + manager->browser()->GetWebContents()->GetRenderWidgetHostView(); + event = view->GetLastMouseDown(); + } + if (!menu_delegate_.get()) menu_delegate_.reset(new CefMenuDelegate); // Create a menu based on the model. menu_.reset(new MenuGtk(menu_delegate_.get(), manager->model())); - gfx::Rect bounds; - manager->browser()->GetWebContents()->GetView()->GetContainerBounds(&bounds); - gfx::Point point = bounds.origin(); - point.Offset(manager->params().x, manager->params().y); - - content::RenderWidgetHostView* view = - manager->browser()->GetWebContents()->GetRenderWidgetHostView(); - GdkEventButton* event = view->GetLastMouseDown(); uint32_t triggering_event_time = event ? event->time : GDK_CURRENT_TIME; // Show the menu. Execution will continue asynchronously. - menu_->PopupAsContext(point, triggering_event_time); + menu_->PopupAsContext(screen_point, triggering_event_time); return true; } diff --git a/cef3/libcef/browser/menu_creator_runner_gtk.h b/cef3/libcef/browser/menu_creator_runner_gtk.h index d113ef717..5a5a44297 100644 --- a/cef3/libcef/browser/menu_creator_runner_gtk.h +++ b/cef3/libcef/browser/menu_creator_runner_gtk.h @@ -14,6 +14,7 @@ class CefMenuCreatorRunnerGtk: public CefMenuCreator::Runner { public: CefMenuCreatorRunnerGtk(); + virtual ~CefMenuCreatorRunnerGtk(); // CefMemoryManager::Runner methods. virtual bool RunContextMenu(CefMenuCreator* manager) OVERRIDE; diff --git a/cef3/libcef/browser/render_widget_host_view_osr.cc b/cef3/libcef/browser/render_widget_host_view_osr.cc index 3ba4c332e..21998775f 100644 --- a/cef3/libcef/browser/render_widget_host_view_osr.cc +++ b/cef3/libcef/browser/render_widget_host_view_osr.cc @@ -192,10 +192,10 @@ void CefRenderWidgetHostViewOSR::UpdateCursor(const WebCursor& cursor) { HCURSOR hCursor = web_cursor.GetCursor((HINSTANCE)hModule); browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange( browser_impl_->GetBrowser(), hCursor); -#elif defined(OS_MACOSX) +#elif defined(OS_MACOSX) || defined(TOOLKIT_GTK) // cursor is const, and GetNativeCursor is not WebCursor web_cursor = cursor; - NSCursor* native_cursor = web_cursor.GetNativeCursor(); + CefCursorHandle native_cursor = web_cursor.GetNativeCursor(); browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange( browser_impl_->GetBrowser(), native_cursor); #else @@ -683,3 +683,14 @@ bool CefRenderWidgetHostViewOSR::IsSpeaking() const { void CefRenderWidgetHostViewOSR::StopSpeaking() { } #endif // defined(OS_MACOSX) + +#if defined(TOOLKIT_GTK) +GdkEventButton* CefRenderWidgetHostViewOSR::GetLastMouseDown() { + return NULL; +} + +gfx::NativeView CefRenderWidgetHostViewOSR::BuildInputMethodsGtkMenu() { + return NULL; +} +#endif // defined(TOOLKIT_GTK) + diff --git a/cef3/libcef/browser/render_widget_host_view_osr.h b/cef3/libcef/browser/render_widget_host_view_osr.h index 2d92b1cc5..877b19bce 100644 --- a/cef3/libcef/browser/render_widget_host_view_osr.h +++ b/cef3/libcef/browser/render_widget_host_view_osr.h @@ -93,14 +93,16 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase { virtual void SetTakesFocusOnlyOnMouseDown(bool flag) OVERRIDE; virtual void SetWindowVisibility(bool visible) OVERRIDE; virtual void WindowFrameChanged() OVERRIDE; - virtual void ShowDefinitionForSelection() OVERRIDE; - virtual bool SupportsSpeech() const OVERRIDE; virtual void SpeakSelection() OVERRIDE; virtual bool IsSpeaking() const OVERRIDE; virtual void StopSpeaking() OVERRIDE; #endif // defined(OS_MACOSX) +#if defined(TOOLKIT_GTK) + virtual GdkEventButton* GetLastMouseDown() OVERRIDE; + virtual gfx::NativeView BuildInputMethodsGtkMenu() OVERRIDE; +#endif // defined(TOOLKIT_GTK) // RenderWidgetHostViewPort methods. virtual void InitAsPopup(RenderWidgetHostView* parent_host_view, diff --git a/cef3/tests/cefclient/cefclient_gtk.cpp b/cef3/tests/cefclient/cefclient_gtk.cpp index f7c658bd5..bb0904cd2 100644 --- a/cef3/tests/cefclient/cefclient_gtk.cpp +++ b/cef3/tests/cefclient/cefclient_gtk.cpp @@ -2,7 +2,12 @@ // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. +// This value is defined in build/common.gypi and must be undefined here +// in order for gtkglext to compile. +#undef GTK_DISABLE_SINGLE_INCLUDES + #include +#include #include #include #include @@ -11,7 +16,9 @@ #include "include/cef_browser.h" #include "include/cef_frame.h" #include "include/cef_runnable.h" +#include "cefclient/cefclient_osr_widget_gtk.h" #include "cefclient/client_handler.h" +#include "cefclient/client_switches.h" #include "cefclient/scheme_test.h" #include "cefclient/string_util.h" @@ -20,6 +27,15 @@ char szWorkingDir[512]; // The current working directory // The global ClientHandler reference. extern CefRefPtr g_handler; +class MainBrowserProvider : public OSRBrowserProvider { + virtual CefRefPtr GetBrowser() { + if (g_handler.get()) + return g_handler->GetBrowser(); + + return NULL; + } +} g_main_browser_provider; + void destroy(GtkWidget* widget, gpointer data) { // Quitting CEF is handled in ClientHandler::OnBeforeClose(). } @@ -248,6 +264,9 @@ int main(int argc, char* argv[]) { gtk_init(&argc, &argv); + // Perform gtkglext initialization required by the OSR example. + gtk_gl_init(&argc, &argv); + // Parse command line arguments. AppInitCommandLine(argc, argv); @@ -324,7 +343,19 @@ int main(int argc, char* argv[]) { CefWindowInfo window_info; CefBrowserSettings browserSettings; - window_info.SetAsChild(vbox); + if (AppIsOffScreenRenderingEnabled()) { + CefRefPtr cmd_line = AppGetCommandLine(); + bool transparent = + cmd_line->HasSwitch(cefclient::kTransparentPaintingEnabled); + + CefRefPtr osr_window = + OSRWindow::Create(&g_main_browser_provider, transparent, vbox); + window_info.SetAsOffScreen(osr_window->GetWindowHandle()); + window_info.SetTransparentPainting(transparent); + g_handler->SetOSRHandler(osr_window.get()); + } else { + window_info.SetAsChild(vbox); + } CefBrowserHost::CreateBrowserSync( window_info, g_handler.get(), diff --git a/cef3/tests/cefclient/cefclient_osr_widget_gtk.cpp b/cef3/tests/cefclient/cefclient_osr_widget_gtk.cpp new file mode 100644 index 000000000..c67a8c7e2 --- /dev/null +++ b/cef3/tests/cefclient/cefclient_osr_widget_gtk.cpp @@ -0,0 +1,491 @@ +// Copyright (c) 2013 The Chromium Embedded Framework 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 "cefclient/cefclient_osr_widget_gtk.h" + +// This value is defined in build/common.gypi and must be undefined here +// in order for gtkglext to compile. +#undef GTK_DISABLE_SINGLE_INCLUDES + +#include +#include +#include +#include +#include + +#include "include/cef_runnable.h" +#include "cefclient/util.h" + +namespace { + +gint glarea_size_allocation(GtkWidget* widget, + GtkAllocation* allocation, + OSRWindow* window) { + CefRefPtr host = window->GetBrowserHost(); + host->WasResized(); + return TRUE; +} + +int get_cef_state_modifiers(guint state) { + int modifiers = 0; + if (state & GDK_SHIFT_MASK) + modifiers |= EVENTFLAG_SHIFT_DOWN; + if (state & GDK_LOCK_MASK) + modifiers |= EVENTFLAG_CAPS_LOCK_ON; + if (state & GDK_CONTROL_MASK) + modifiers |= EVENTFLAG_CONTROL_DOWN; + if (state & GDK_MOD1_MASK) + modifiers |= EVENTFLAG_ALT_DOWN; + if (state & GDK_BUTTON1_MASK) + modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON; + if (state & GDK_BUTTON2_MASK) + modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON; + if (state & GDK_BUTTON3_MASK) + modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON; + return modifiers; +} + +gint glarea_click_event(GtkWidget* widget, + GdkEventButton* event, + OSRWindow* window) { + CefRefPtr host = window->GetBrowserHost(); + + CefBrowserHost::MouseButtonType button_type = MBT_LEFT; + switch (event->button) { + case 1: + break; + case 2: + button_type = MBT_MIDDLE; + break; + case 3: + button_type = MBT_RIGHT; + break; + default: + // Other mouse buttons are not handled here. + return FALSE; + } + + CefMouseEvent mouse_event; + mouse_event.x = event->x; + mouse_event.y = event->y; + window->ApplyPopupOffset(mouse_event.x, mouse_event.y); + mouse_event.modifiers = get_cef_state_modifiers(event->state); + + bool mouse_up = (event->type == GDK_BUTTON_RELEASE); + if (!mouse_up) + gtk_widget_grab_focus(widget); + + int click_count = 1; + switch (event->type) { + case GDK_2BUTTON_PRESS: + click_count = 2; + break; + case GDK_3BUTTON_PRESS: + click_count = 3; + break; + default: + break; + } + + host->SendMouseClickEvent(mouse_event, button_type, mouse_up, click_count); + return TRUE; +} + +gint glarea_move_event(GtkWidget* widget, + GdkEventMotion* event, + OSRWindow* window) { + gint x, y; + GdkModifierType state; + + if (event->is_hint) { + gdk_window_get_pointer(event->window, &x, &y, &state); + } else { + x = (gint)event->x; + y = (gint)event->y; + state = (GdkModifierType)event->state; + } + + CefRefPtr host = window->GetBrowserHost(); + + CefMouseEvent mouse_event; + mouse_event.x = x; + mouse_event.y = y; + window->ApplyPopupOffset(mouse_event.x, mouse_event.y); + mouse_event.modifiers = get_cef_state_modifiers(state); + + bool mouse_leave = (event->type == GDK_LEAVE_NOTIFY); + + host->SendMouseMoveEvent(mouse_event, mouse_leave); + return TRUE; +} + +gint glarea_scroll_event(GtkWidget* widget, + GdkEventScroll* event, + OSRWindow* window) { + CefRefPtr host = window->GetBrowserHost(); + + CefMouseEvent mouse_event; + mouse_event.x = event->x; + mouse_event.y = event->y; + window->ApplyPopupOffset(mouse_event.x, mouse_event.y); + mouse_event.modifiers = get_cef_state_modifiers(event->state); + + static const int scrollbarPixelsPerGtkTick = 40; + int deltaX = 0; + int deltaY = 0; + switch (event->direction) { + case GDK_SCROLL_UP: + deltaY = scrollbarPixelsPerGtkTick; + break; + case GDK_SCROLL_DOWN: + deltaY = -scrollbarPixelsPerGtkTick; + break; + case GDK_SCROLL_LEFT: + deltaX = scrollbarPixelsPerGtkTick; + break; + case GDK_SCROLL_RIGHT: + deltaX = -scrollbarPixelsPerGtkTick; + break; + } + + host->SendMouseWheelEvent(mouse_event, deltaX, deltaY); + return TRUE; +} + +gint glarea_key_event(GtkWidget* widget, + GdkEventKey* event, + OSRWindow* window) { + CefRefPtr host = window->GetBrowserHost(); + + CefKeyEvent key_event; + key_event.native_key_code = event->keyval; + key_event.modifiers = get_cef_state_modifiers(event->state); + + if (event->type == GDK_KEY_PRESS) { + key_event.type = KEYEVENT_RAWKEYDOWN; + host->SendKeyEvent(key_event); + } else { + // Need to send both KEYUP and CHAR events. + key_event.type = KEYEVENT_KEYUP; + host->SendKeyEvent(key_event); + key_event.type = KEYEVENT_CHAR; + host->SendKeyEvent(key_event); + } + + return TRUE; +} + +gint glarea_focus_event(GtkWidget* widget, + GdkEventFocus* event, + OSRWindow* window) { + CefRefPtr host = window->GetBrowserHost(); + host->SendFocusEvent(event->in == TRUE); + return TRUE; +} + +void widget_get_rect_in_screen(GtkWidget* widget, GdkRectangle* r) { + gint x, y, w, h; + GdkRectangle extents; + + GdkWindow* window = gtk_widget_get_parent_window(widget); + + // Get parent's left-top screen coordinates. + gdk_window_get_root_origin(window, &x, &y); + // Get parent's width and height. + gdk_drawable_get_size(window, &w, &h); + // Get parent's extents including decorations. + gdk_window_get_frame_extents(window, &extents); + + // X and Y calculations assume that left, right and bottom border sizes are + // all the same. + const gint border = (extents.width - w) / 2; + r->x = x + border + widget->allocation.x; + r->y = y + (extents.height - h) - border + widget->allocation.y; + r->width = widget->allocation.width; + r->height = widget->allocation.height; +} + +class ScopedGLContext { + public: + ScopedGLContext(GtkWidget* widget, bool swap_buffers) + : swap_buffers_(swap_buffers) { + GdkGLContext* glcontext = gtk_widget_get_gl_context(widget); + gldrawable_ = gtk_widget_get_gl_drawable(widget); + is_valid_ = gdk_gl_drawable_gl_begin(gldrawable_, glcontext); + } + + virtual ~ScopedGLContext() { + if (is_valid_) { + gdk_gl_drawable_gl_end(gldrawable_); + + if(swap_buffers_) { + if (gdk_gl_drawable_is_double_buffered(gldrawable_)) + gdk_gl_drawable_swap_buffers(gldrawable_); + else + glFlush(); + } + } + } + + bool IsValid() const { return is_valid_; } + + private: + bool swap_buffers_; + GdkGLContext* glcontext_; + GdkGLDrawable* gldrawable_; + bool is_valid_; +}; + +} // namespace + +// static +CefRefPtr OSRWindow::Create(OSRBrowserProvider* browser_provider, + bool transparent, + CefWindowHandle parentView) { + ASSERT(browser_provider); + if (!browser_provider) + return NULL; + + return new OSRWindow(browser_provider, transparent, parentView); +} + +// static +CefRefPtr OSRWindow::From( + CefRefPtr renderHandler) { + return static_cast(renderHandler.get()); +} + +void OSRWindow::OnBeforeClose(CefRefPtr browser) { + // Disconnect all signal handlers that reference |this|. + g_signal_handlers_disconnect_by_data(glarea_, this); + + DisableGL(); +} + +bool OSRWindow::GetViewRect(CefRefPtr browser, + CefRect& rect) { + if (!glarea_) + return false; + + // The simulated screen and view rectangle are the same. This is necessary + // for popup menus to be located and sized inside the view. + rect.x = rect.y = 0; + rect.width = glarea_->allocation.width; + rect.height = glarea_->allocation.height; + return true; +} + +bool OSRWindow::GetScreenPoint(CefRefPtr browser, + int viewX, + int viewY, + int& screenX, + int& screenY) { + GdkRectangle screen_rect; + widget_get_rect_in_screen(glarea_, &screen_rect); + screenX = screen_rect.x + viewX; + screenY = screen_rect.y + viewY; + return true; +} + +void OSRWindow::OnPopupShow(CefRefPtr browser, + bool show) { + if (!show) { + CefRect dirty_rect = renderer_.popup_rect(); + renderer_.ClearPopupRects(); + browser->GetHost()->Invalidate(dirty_rect, PET_VIEW); + } + renderer_.OnPopupShow(browser, show); +} + +void OSRWindow::OnPopupSize(CefRefPtr browser, + const CefRect& rect) { + renderer_.OnPopupSize(browser, rect); +} + +void OSRWindow::OnPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const void* buffer, + int width, int height) { + if (painting_popup_) { + renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height); + return; + } + + if (!gl_enabled_) + EnableGL(); + + ScopedGLContext scoped_gl_context(glarea_, true); + if (!scoped_gl_context.IsValid()) + return; + + renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height); + if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) { + painting_popup_ = true; + CefRect client_popup_rect(0, 0, + renderer_.popup_rect().width, + renderer_.popup_rect().height); + browser->GetHost()->Invalidate(client_popup_rect, PET_POPUP); + painting_popup_ = false; + } + renderer_.Render(); +} + +void OSRWindow::OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor) { + GtkWidget* window = gtk_widget_get_toplevel(glarea_); + GdkWindow* gdk_window = gtk_widget_get_window(window); + if (cursor->type == GDK_LAST_CURSOR) + cursor = NULL; + gdk_window_set_cursor(gdk_window, cursor); +} + +void OSRWindow::Invalidate() { + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, NewCefRunnableMethod(this, &OSRWindow::Invalidate)); + return; + } + + // Don't post another task if the previous task is still pending. + if (render_task_pending_) + return; + + render_task_pending_ = true; + + // Render at 30fps. + static const int kRenderDelay = 1000 / 30; + CefPostDelayedTask(TID_UI, NewCefRunnableMethod(this, &OSRWindow::Render), + kRenderDelay); +} + +bool OSRWindow::IsOverPopupWidget(int x, int y) const { + const CefRect& rc = renderer_.popup_rect(); + int popup_right = rc.x + rc.width; + int popup_bottom = rc.y + rc.height; + return (x >= rc.x) && (x < popup_right) && + (y >= rc.y) && (y < popup_bottom); +} + +int OSRWindow::GetPopupXOffset() const { + return renderer_.original_popup_rect().x - renderer_.popup_rect().x; +} + +int OSRWindow::GetPopupYOffset() const { + return renderer_.original_popup_rect().y - renderer_.popup_rect().y; +} + +void OSRWindow::ApplyPopupOffset(int& x, int& y) const { + if (IsOverPopupWidget(x, y)) { + x += GetPopupXOffset(); + y += GetPopupYOffset(); + } +} + +OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider, + bool transparent, + CefWindowHandle parentView) + : renderer_(transparent), + browser_provider_(browser_provider), + gl_enabled_(false), + painting_popup_(false), + render_task_pending_(false) { + glarea_ = gtk_drawing_area_new(); + ASSERT(glarea_); + + GdkGLConfig* glconfig = gdk_gl_config_new_by_mode( + static_cast(GDK_GL_MODE_RGB | + GDK_GL_MODE_DEPTH | + GDK_GL_MODE_DOUBLE)); + ASSERT(glconfig); + + gtk_widget_set_gl_capability(glarea_, glconfig, NULL, TRUE, + GDK_GL_RGBA_TYPE); + + gtk_widget_set_can_focus(glarea_, TRUE); + + g_signal_connect(G_OBJECT(glarea_), "size_allocate", + G_CALLBACK(glarea_size_allocation), this); + + gtk_widget_set_events(glarea_, + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_SCROLL_MASK | + GDK_FOCUS_CHANGE_MASK); + g_signal_connect(G_OBJECT(glarea_), "button_press_event", + G_CALLBACK(glarea_click_event), this); + g_signal_connect(G_OBJECT(glarea_), "button_release_event", + G_CALLBACK(glarea_click_event), this); + g_signal_connect(G_OBJECT(glarea_), "key_press_event", + G_CALLBACK(glarea_key_event), this); + g_signal_connect(G_OBJECT(glarea_), "key_release_event", + G_CALLBACK(glarea_key_event), this); + g_signal_connect(G_OBJECT(glarea_), "enter_notify_event", + G_CALLBACK(glarea_move_event), this); + g_signal_connect(G_OBJECT(glarea_), "leave_notify_event", + G_CALLBACK(glarea_move_event), this); + g_signal_connect(G_OBJECT(glarea_), "motion_notify_event", + G_CALLBACK(glarea_move_event), this); + g_signal_connect(G_OBJECT(glarea_), "scroll_event", + G_CALLBACK(glarea_scroll_event), this); + g_signal_connect(G_OBJECT(glarea_), "focus_in_event", + G_CALLBACK(glarea_focus_event), this); + g_signal_connect(G_OBJECT(glarea_), "focus_out_event", + G_CALLBACK(glarea_focus_event), this); + + gtk_container_add(GTK_CONTAINER(parentView), glarea_); +} + +OSRWindow::~OSRWindow() { +} + +void OSRWindow::Render() { + ASSERT(CefCurrentlyOn(TID_UI)); + if (render_task_pending_) + render_task_pending_ = false; + + if (!gl_enabled_) + EnableGL(); + + ScopedGLContext scoped_gl_context(glarea_, true); + if (!scoped_gl_context.IsValid()) + return; + + renderer_.Render(); +} + +void OSRWindow::EnableGL() { + ASSERT(CefCurrentlyOn(TID_UI)); + if (gl_enabled_) + return; + + ScopedGLContext scoped_gl_context(glarea_, false); + if (!scoped_gl_context.IsValid()) + return; + + renderer_.Initialize(); + + gl_enabled_ = true; +} + +void OSRWindow::DisableGL() { + ASSERT(CefCurrentlyOn(TID_UI)); + + if (!gl_enabled_) + return; + + ScopedGLContext scoped_gl_context(glarea_, false); + if (!scoped_gl_context.IsValid()) + return; + + renderer_.Cleanup(); + + gl_enabled_ = false; +} + diff --git a/cef3/tests/cefclient/cefclient_osr_widget_gtk.h b/cef3/tests/cefclient/cefclient_osr_widget_gtk.h new file mode 100644 index 000000000..9bab8dae9 --- /dev/null +++ b/cef3/tests/cefclient/cefclient_osr_widget_gtk.h @@ -0,0 +1,90 @@ +// Copyright (c) 2013 The Chromium Embedded Framework 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 CEF_TESTS_CEFCLIENT_CEFCLIENT_OSR_WIDGET_GTK_H_ +#define CEF_TESTS_CEFCLIENT_CEFCLIENT_OSR_WIDGET_GTK_H_ +#pragma once + +#include "include/cef_render_handler.h" +#include "cefclient/client_handler.h" +#include "cefclient/osrenderer.h" + +class OSRBrowserProvider { + public: + virtual CefRefPtr GetBrowser() =0; + + protected: + virtual ~OSRBrowserProvider() {} +}; + +class OSRWindow : public ClientHandler::RenderHandler { + public: + // Create a new OSRWindow instance. |browser_provider| must outlive this + // object. + static CefRefPtr Create(OSRBrowserProvider* browser_provider, + bool transparent, + CefWindowHandle parentView); + + static CefRefPtr From( + CefRefPtr renderHandler); + + CefWindowHandle GetWindowHandle() const { + return glarea_; + } + CefRefPtr GetBrowserHost() const { + return browser_provider_->GetBrowser()->GetHost(); + } + + // ClientHandler::RenderHandler methods + virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE; + + // CefRenderHandler methods + virtual bool GetViewRect(CefRefPtr browser, + CefRect& rect) OVERRIDE; + virtual bool GetScreenPoint(CefRefPtr browser, + int viewX, + int viewY, + int& screenX, + int& screenY) OVERRIDE; + virtual void OnPopupShow(CefRefPtr browser, + bool show) OVERRIDE; + virtual void OnPopupSize(CefRefPtr browser, + const CefRect& rect) OVERRIDE; + virtual void OnPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const void* buffer, + int width, + int height) OVERRIDE; + virtual void OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor) OVERRIDE; + + void Invalidate(); + bool IsOverPopupWidget(int x, int y) const; + int GetPopupXOffset() const; + int GetPopupYOffset() const; + void ApplyPopupOffset(int& x, int& y) const; + + private: + OSRWindow(OSRBrowserProvider* browser_provider, + bool transparent, + CefWindowHandle parentView); + virtual ~OSRWindow(); + + void Render(); + void EnableGL(); + void DisableGL(); + + ClientOSRenderer renderer_; + OSRBrowserProvider* browser_provider_; + CefWindowHandle glarea_; + bool gl_enabled_; + + bool painting_popup_; + bool render_task_pending_; + + IMPLEMENT_REFCOUNTING(OSRWindow); +}; + +#endif // CEF_TESTS_CEFCLIENT_CEFCLIENT_OSR_WIDGET_GTK_H_ diff --git a/cef3/tests/cefclient/osrenderer.cpp b/cef3/tests/cefclient/osrenderer.cpp index dabfe3b4e..a8c0dda3e 100644 --- a/cef3/tests/cefclient/osrenderer.cpp +++ b/cef3/tests/cefclient/osrenderer.cpp @@ -9,6 +9,9 @@ #include #elif defined(OS_MACOSX) #include +#elif defined(OS_LINUX) +#include +#include #else #error Platform is not supported. #endif diff --git a/cef3/tests/cefclient/res/osr_test.html b/cef3/tests/cefclient/res/osr_test.html index 9d78e9529..3136bdef4 100644 --- a/cef3/tests/cefclient/res/osr_test.html +++ b/cef3/tests/cefclient/res/osr_test.html @@ -52,7 +52,7 @@
  • Invalidate should trigger OnPaint once
  • Click and write here with SendKeyEvent to trigger repaints: -
  • +
  • Click here with SendMouseClickEvent to navigate:
  • diff --git a/cef3/tests/unittests/os_rendering_unittest.cc b/cef3/tests/unittests/os_rendering_unittest.cc index ebbd56851..c3b88ea13 100644 --- a/cef3/tests/unittests/os_rendering_unittest.cc +++ b/cef3/tests/unittests/os_rendering_unittest.cc @@ -16,6 +16,8 @@ #if defined(OS_MACOSX) #include "tests/unittests/os_rendering_unittest_mac.h" +#elif defined(OS_LINUX) +#include #elif defined(OS_WIN) // Required for resource_util_win, which uses this as an extern HINSTANCE hInst = ::GetModuleHandle(NULL); @@ -35,7 +37,7 @@ const int kOsrWidth = 600; const int kOsrHeight = 400; // precomputed bounding client rects for html elements (h1 and li). -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) const CefRect kExpectedRectLI[] = { CefRect(8, 8, 567, 74), // LI00 CefRect(27, 103, 548, 20), // LI01 @@ -69,26 +71,34 @@ const CefRect kExpectedRectLI[] = { // bounding client rects for edit box and navigate button #if defined(OS_WIN) -const CefRect kEditBoxRect(412, 245, 153, 22); +const CefRect kEditBoxRect(412, 245, 60, 22); const CefRect kNavigateButtonRect(360, 271, 140, 22); const CefRect kSelectRect(467, 22, 75, 20); const CefRect kExpandedSelectRect(467, 42, 81, 322); +const int kDefaultVerticalScrollbarWidth = 17; const int kVerticalScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL); const int kHorizontalScrollbarWidth = GetSystemMetrics(SM_CXHSCROLL); #elif defined(OS_MACOSX) -const CefRect kEditBoxRect(429, 228, 129, 25); +const CefRect kEditBoxRect(429, 228, 60, 25); const CefRect kNavigateButtonRect(375, 251, 138, 28); const CefRect kSelectRect(461, 21, 87, 26); const CefRect kExpandedSelectRect(467, 42, 80, 262); +#elif defined(OS_LINUX) +const CefRect kEditBoxRect(434, 246, 60, 20); +const CefRect kNavigateButtonRect(380, 271, 140, 22); +const CefRect kSelectRect(467, 22, 75, 20); +const CefRect kExpandedSelectRect(467, 42, 79, 322); +const int kDefaultVerticalScrollbarWidth = 14; +const int kVerticalScrollbarWidth = 14; +const int kHorizontalScrollbarWidth = 14; #else #error "Unsupported platform" #endif // defined(OS_WIN) // adjusted expected rect regarding system vertical scrollbar width CefRect ExpectedRect(int index) { -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) // this is the scrollbar width for all the kExpectedRectLI - const int kDefaultVerticalScrollbarWidth = 17; if (kDefaultVerticalScrollbarWidth == kVerticalScrollbarWidth) return kExpectedRectLI[index]; @@ -106,12 +116,21 @@ CefRect ExpectedRect(int index) { // word to be written into edit box const char kKeyTestWord[] = "done"; +#if defined(OS_MACOSX) const ui::KeyboardCode kKeyTestCodes[] = { ui::VKEY_D, ui::VKEY_O, ui::VKEY_N, ui::VKEY_E }; +#elif defined(OS_LINUX) +const unsigned int kKeyTestCodes[] = { + XK_d, + XK_o, + XK_n, + XK_e +}; +#endif // width for the icon that appear on the screen when pressing // middle mouse button @@ -210,10 +229,13 @@ class OSRTestHandler : public TestHandler, return; switch(test_type_) { - case OSR_TEST_KEY_EVENTS: - EXPECT_EQ(frame->GetURL(), std::string(kTestUrl) + "?k=" + kKeyTestWord); + case OSR_TEST_KEY_EVENTS: { + const std::string& expected_url = + std::string(kTestUrl) + "?k=" + kKeyTestWord; + EXPECT_STREQ(expected_url.c_str(), + frame->GetURL().ToString().c_str()); DestroySucceededTestSoon(); - break; + } break; default: // Intentionally left blank break; @@ -544,6 +566,8 @@ class OSRTestHandler : public TestHandler, event.windows_key_code = VkCode; #elif defined(OS_MACOSX) osr_unittests::GetKeyEvent(event, kKeyTestCodes[i], 0); +#elif defined(OS_LINUX) + event.native_key_code = kKeyTestCodes[i]; #else NOTREACHED(); #endif @@ -553,6 +577,8 @@ class OSRTestHandler : public TestHandler, event.windows_key_code = kKeyTestWord[i]; #elif defined(OS_MACOSX) osr_unittests::GetKeyEvent(event, kKeyTestCodes[i], 0); +#elif defined(OS_LINUX) + event.native_key_code = kKeyTestCodes[i]; #endif event.type = KEYEVENT_CHAR; browser->GetHost()->SendKeyEvent(event); @@ -562,6 +588,8 @@ class OSRTestHandler : public TestHandler, event.native_key_code |= 0xC0000000; #elif defined(OS_MACOSX) osr_unittests::GetKeyEvent(event, kKeyTestCodes[i], 0); +#elif defined(OS_LINUX) + event.native_key_code = kKeyTestCodes[i]; #endif event.type = KEYEVENT_KEYUP; browser->GetHost()->SendKeyEvent(event); @@ -623,6 +651,11 @@ class OSRTestHandler : public TestHandler, EXPECT_EQ(dirtyRects[0], CefRect(0, 0, kOsrWidth, kOsrHeight)); DestroySucceededTestSoon(); +#elif defined(OS_LINUX) + EXPECT_EQ(dirtyRects.size(), 1U); + EXPECT_EQ(dirtyRects[0], CefRect(0, 0, + kOsrWidth, kOsrHeight)); + DestroySucceededTestSoon(); #else #error "Unsupported platform" #endif // defined(OS_WIN) @@ -672,10 +705,12 @@ class OSRTestHandler : public TestHandler, BYTE VkCode = LOBYTE(VK_ESCAPE); UINT scanCode = MapVirtualKey(VkCode, MAPVK_VK_TO_VSC); event.native_key_code = (scanCode << 16) | // key scan code - 1; // key repeat count + 1; // key repeat count event.windows_key_code = VkCode; #elif defined(OS_MACOSX) osr_unittests::GetKeyEvent(event, ui::VKEY_ESCAPE, 0); +#elif defined(OS_LINUX) + event.native_key_code = XK_Escape; #else #error "Unsupported platform" #endif // defined(OS_WIN) @@ -729,7 +764,7 @@ class OSRTestHandler : public TestHandler, 1, kExpandedSelectRect.width - 3, kExpandedSelectRect.height - 2)); -#elif defined(OS_MACOSX) +#elif defined(OS_MACOSX) || defined(OS_LINUX) EXPECT_EQ(dirtyRects[0], CefRect(1, 0, @@ -758,8 +793,8 @@ class OSRTestHandler : public TestHandler, virtual bool OnTooltip(CefRefPtr browser, CefString& text) OVERRIDE { - if (test_type_ == OSR_TEST_TOOLTIP && started()) { - EXPECT_EQ(text, "EXPECTED_TOOLTIP"); + if (test_type_ == OSR_TEST_TOOLTIP && started()) { + EXPECT_STREQ("EXPECTED_TOOLTIP", text.ToString().c_str()); DestroySucceededTestSoon(); } return false; @@ -794,6 +829,8 @@ class OSRTestHandler : public TestHandler, windowInfo.SetAsOffScreen(osr_unittests::GetFakeView()); else windowInfo.SetAsOffScreen(NULL); +#elif defined(OS_LINUX) + windowInfo.SetAsOffScreen(NULL); #else #error "Unsupported platform" #endif diff --git a/cef3/tools/distrib/cefclient.gyp b/cef3/tools/distrib/cefclient.gyp index 388920052..7e33a547b 100644 --- a/cef3/tools/distrib/cefclient.gyp +++ b/cef3/tools/distrib/cefclient.gyp @@ -315,7 +315,8 @@ 'variables': { # gtk requires gmodule, but it does not list it as a dependency # in some misconfigured systems. - 'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0', + # gtkglext is required by the cefclient OSR example. + 'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0 gtkglext-1.0', }, 'direct_dependent_settings': { 'cflags': [