2015-11-17 19:20:13 +01:00
|
|
|
// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
|
2014-05-22 23:01:22 +02:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
#include "libcef/browser/native/browser_platform_delegate_native_linux.h"
|
2014-05-22 23:01:22 +02:00
|
|
|
|
2020-09-25 03:40:47 +02:00
|
|
|
#include "libcef/browser/browser_host_base.h"
|
2014-05-22 23:01:22 +02:00
|
|
|
#include "libcef/browser/context.h"
|
2015-11-17 19:20:13 +01:00
|
|
|
#include "libcef/browser/native/menu_runner_linux.h"
|
|
|
|
#include "libcef/browser/native/window_delegate_view.h"
|
2014-05-22 23:01:22 +02:00
|
|
|
#include "libcef/browser/thread_util.h"
|
|
|
|
|
2018-11-03 02:15:09 +01:00
|
|
|
#include "base/no_destructor.h"
|
2014-10-29 19:14:47 +01:00
|
|
|
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
2014-05-22 23:01:22 +02:00
|
|
|
#include "content/public/browser/native_web_keyboard_event.h"
|
2014-10-29 19:14:47 +01:00
|
|
|
#include "content/public/browser/render_view_host.h"
|
2019-04-24 04:50:25 +02:00
|
|
|
#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
|
2016-07-06 21:34:09 +02:00
|
|
|
#include "ui/events/keycodes/dom/dom_key.h"
|
|
|
|
#include "ui/events/keycodes/dom/keycode_converter.h"
|
|
|
|
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
|
|
|
|
#include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
|
|
|
|
#include "ui/events/keycodes/keysym_to_unicode.h"
|
2015-11-17 19:20:13 +01:00
|
|
|
#include "ui/gfx/font_render_params.h"
|
2014-05-22 23:01:22 +02:00
|
|
|
#include "ui/views/widget/widget.h"
|
|
|
|
|
2019-04-23 19:00:14 +02:00
|
|
|
#if defined(USE_X11)
|
|
|
|
#include "libcef/browser/native/window_x11.h"
|
2020-08-29 00:39:23 +02:00
|
|
|
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
|
2019-04-23 19:00:14 +02:00
|
|
|
#endif
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
CefBrowserPlatformDelegateNativeLinux::CefBrowserPlatformDelegateNativeLinux(
|
2017-04-20 21:28:17 +02:00
|
|
|
const CefWindowInfo& window_info,
|
2020-07-04 20:21:34 +02:00
|
|
|
SkColor background_color)
|
|
|
|
: CefBrowserPlatformDelegateNativeAura(window_info, background_color),
|
2015-11-17 19:20:13 +01:00
|
|
|
host_window_created_(false),
|
2019-04-23 19:00:14 +02:00
|
|
|
window_widget_(nullptr) {}
|
2014-07-01 00:30:29 +02:00
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
void CefBrowserPlatformDelegateNativeLinux::BrowserDestroyed(
|
2020-09-25 03:40:47 +02:00
|
|
|
CefBrowserHostBase* browser) {
|
2020-07-04 20:21:34 +02:00
|
|
|
CefBrowserPlatformDelegateNative::BrowserDestroyed(browser);
|
2014-05-22 23:01:22 +02:00
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
if (host_window_created_) {
|
|
|
|
// Release the reference added in CreateHostWindow().
|
|
|
|
browser->Release();
|
2014-07-01 00:30:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() {
|
2014-05-22 23:01:22 +02:00
|
|
|
DCHECK(!window_widget_);
|
|
|
|
|
|
|
|
if (window_info_.width == 0)
|
|
|
|
window_info_.width = 800;
|
|
|
|
if (window_info_.height == 0)
|
|
|
|
window_info_.height = 600;
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
gfx::Rect rect(window_info_.x, window_info_.y, window_info_.width,
|
|
|
|
window_info_.height);
|
2014-05-22 23:01:22 +02:00
|
|
|
|
2019-04-23 19:00:14 +02:00
|
|
|
#if defined(USE_X11)
|
|
|
|
DCHECK(!window_x11_);
|
2020-10-08 21:54:42 +02:00
|
|
|
|
|
|
|
x11::Window parent_window = x11::Window::None;
|
|
|
|
if (window_info_.parent_window != kNullWindowHandle) {
|
|
|
|
parent_window = static_cast<x11::Window>(window_info_.parent_window);
|
|
|
|
}
|
|
|
|
|
2014-05-22 23:01:22 +02:00
|
|
|
// Create a new window object. It will delete itself when the associated X11
|
|
|
|
// window is destroyed.
|
2019-04-24 04:50:25 +02:00
|
|
|
window_x11_ =
|
2020-10-08 21:54:42 +02:00
|
|
|
new CefWindowX11(browser_, parent_window, rect,
|
2019-04-24 04:50:25 +02:00
|
|
|
CefString(&window_info_.window_name).ToString());
|
2020-10-08 21:54:42 +02:00
|
|
|
DCHECK_NE(window_x11_->xwindow(), x11::Window::None);
|
|
|
|
window_info_.window =
|
|
|
|
static_cast<cef_window_handle_t>(window_x11_->xwindow());
|
2014-05-22 23:01:22 +02:00
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
host_window_created_ = true;
|
|
|
|
|
|
|
|
// Add a reference that will be released in BrowserDestroyed().
|
|
|
|
browser_->AddRef();
|
2014-05-22 23:01:22 +02:00
|
|
|
|
2018-02-28 05:47:36 +01:00
|
|
|
CefWindowDelegateView* delegate_view = new CefWindowDelegateView(
|
2019-07-17 20:47:27 +02:00
|
|
|
GetBackgroundColor(), window_x11_->TopLevelAlwaysOnTop(),
|
|
|
|
GetBoundsChangedCallback());
|
2020-08-29 00:39:23 +02:00
|
|
|
delegate_view->Init(static_cast<gfx::AcceleratedWidget>(window_info_.window),
|
|
|
|
web_contents_, gfx::Rect(gfx::Point(), rect.size()));
|
2014-05-22 23:01:22 +02:00
|
|
|
|
|
|
|
window_widget_ = delegate_view->GetWidget();
|
|
|
|
window_widget_->Show();
|
|
|
|
|
|
|
|
window_x11_->Show();
|
2019-04-23 19:00:14 +02:00
|
|
|
#endif // defined(USE_X11)
|
2014-05-22 23:01:22 +02:00
|
|
|
|
|
|
|
// As an additional requirement on Linux, we must set the colors for the
|
|
|
|
// render widgets in webkit.
|
2020-12-02 23:31:49 +01:00
|
|
|
auto prefs = web_contents_->GetMutableRendererPrefs();
|
2014-05-22 23:01:22 +02:00
|
|
|
prefs->focus_ring_color = SkColorSetARGB(255, 229, 151, 0);
|
|
|
|
|
|
|
|
prefs->active_selection_bg_color = SkColorSetRGB(30, 144, 255);
|
|
|
|
prefs->active_selection_fg_color = SK_ColorWHITE;
|
|
|
|
prefs->inactive_selection_bg_color = SkColorSetRGB(200, 200, 200);
|
|
|
|
prefs->inactive_selection_fg_color = SkColorSetRGB(50, 50, 50);
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
// Set font-related attributes.
|
2021-07-23 18:40:13 +02:00
|
|
|
static const gfx::FontRenderParams params(
|
2018-11-03 02:15:09 +01:00
|
|
|
gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr));
|
2021-07-23 18:40:13 +02:00
|
|
|
prefs->should_antialias_text = params.antialiasing;
|
|
|
|
prefs->use_subpixel_positioning = params.subpixel_positioning;
|
|
|
|
prefs->hinting = params.hinting;
|
|
|
|
prefs->use_autohinter = params.autohinter;
|
|
|
|
prefs->use_bitmaps = params.use_bitmaps;
|
|
|
|
prefs->subpixel_rendering = params.subpixel_rendering;
|
2015-11-17 19:20:13 +01:00
|
|
|
|
2020-07-08 19:23:29 +02:00
|
|
|
web_contents_->SyncRendererPrefs();
|
2015-11-17 19:20:13 +01:00
|
|
|
|
2014-05-22 23:01:22 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
void CefBrowserPlatformDelegateNativeLinux::CloseHostWindow() {
|
2019-04-23 19:00:14 +02:00
|
|
|
#if defined(USE_X11)
|
2014-05-22 23:01:22 +02:00
|
|
|
if (window_x11_)
|
|
|
|
window_x11_->Close();
|
2019-04-23 19:00:14 +02:00
|
|
|
#endif
|
2014-05-22 23:01:22 +02:00
|
|
|
}
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
CefWindowHandle CefBrowserPlatformDelegateNativeLinux::GetHostWindowHandle()
|
|
|
|
const {
|
2015-11-17 19:20:13 +01:00
|
|
|
if (windowless_handler_)
|
|
|
|
return windowless_handler_->GetParentWindowHandle();
|
|
|
|
return window_info_.window;
|
|
|
|
}
|
|
|
|
|
|
|
|
views::Widget* CefBrowserPlatformDelegateNativeLinux::GetWindowWidget() const {
|
|
|
|
return window_widget_;
|
2014-05-22 23:01:22 +02:00
|
|
|
}
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
void CefBrowserPlatformDelegateNativeLinux::SendFocusEvent(bool setFocus) {
|
|
|
|
if (!setFocus)
|
2014-06-06 21:04:21 +02:00
|
|
|
return;
|
|
|
|
|
2020-07-08 19:23:29 +02:00
|
|
|
if (web_contents_) {
|
2014-06-06 21:04:21 +02:00
|
|
|
// Give logical focus to the RenderWidgetHostViewAura in the views
|
|
|
|
// hierarchy. This does not change the native keyboard focus.
|
2020-07-08 19:23:29 +02:00
|
|
|
web_contents_->Focus();
|
2014-06-06 21:04:21 +02:00
|
|
|
}
|
|
|
|
|
2019-04-23 19:00:14 +02:00
|
|
|
#if defined(USE_X11)
|
2014-06-06 21:04:21 +02:00
|
|
|
if (window_x11_) {
|
|
|
|
// Give native focus to the DesktopNativeWidgetAura for the root window.
|
|
|
|
// Needs to be done via the ::Window so that keyboard focus is assigned
|
|
|
|
// correctly.
|
|
|
|
window_x11_->Focus();
|
|
|
|
}
|
2019-04-23 19:00:14 +02:00
|
|
|
#endif // defined(USE_X11)
|
2014-06-06 21:04:21 +02:00
|
|
|
}
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
void CefBrowserPlatformDelegateNativeLinux::NotifyMoveOrResizeStarted() {
|
|
|
|
// Call the parent method to dismiss any existing popups.
|
2020-07-04 20:21:34 +02:00
|
|
|
CefBrowserPlatformDelegateNative::NotifyMoveOrResizeStarted();
|
2015-11-17 19:20:13 +01:00
|
|
|
|
2020-07-08 19:23:29 +02:00
|
|
|
if (!web_contents_)
|
|
|
|
return;
|
|
|
|
|
2019-04-23 19:00:14 +02:00
|
|
|
#if defined(USE_X11)
|
2015-11-17 19:20:13 +01:00
|
|
|
if (!window_x11_)
|
|
|
|
return;
|
|
|
|
|
2020-08-29 00:39:23 +02:00
|
|
|
views::DesktopWindowTreeHostLinux* tree_host = window_x11_->GetHost();
|
2015-11-17 19:20:13 +01:00
|
|
|
if (!tree_host)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Explicitly set the screen bounds so that WindowTreeHost::*Screen()
|
|
|
|
// methods return the correct results.
|
|
|
|
const gfx::Rect& bounds = window_x11_->GetBoundsInScreen();
|
|
|
|
tree_host->set_screen_bounds(bounds);
|
|
|
|
|
|
|
|
// Send updated screen rectangle information to the renderer process so that
|
|
|
|
// popups are displayed in the correct location.
|
|
|
|
content::RenderWidgetHostImpl::From(
|
2020-07-08 19:23:29 +02:00
|
|
|
web_contents_->GetRenderViewHost()->GetWidget())
|
2017-05-17 11:29:28 +02:00
|
|
|
->SendScreenRects();
|
2019-04-23 19:00:14 +02:00
|
|
|
#endif // defined(USE_X11)
|
2015-11-17 19:20:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefBrowserPlatformDelegateNativeLinux::SizeTo(int width, int height) {
|
2019-04-23 19:00:14 +02:00
|
|
|
#if defined(USE_X11)
|
2015-11-17 19:20:13 +01:00
|
|
|
if (window_x11_) {
|
|
|
|
window_x11_->SetBounds(
|
|
|
|
gfx::Rect(window_x11_->bounds().origin(), gfx::Size(width, height)));
|
|
|
|
}
|
2019-04-23 19:00:14 +02:00
|
|
|
#endif // defined(USE_X11)
|
2014-05-22 23:01:22 +02:00
|
|
|
}
|
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
gfx::Point CefBrowserPlatformDelegateNativeLinux::GetScreenPoint(
|
|
|
|
const gfx::Point& view) const {
|
|
|
|
if (windowless_handler_)
|
|
|
|
return windowless_handler_->GetParentScreenPoint(view);
|
|
|
|
|
2019-04-23 19:00:14 +02:00
|
|
|
#if defined(USE_X11)
|
2015-11-17 19:20:13 +01:00
|
|
|
if (!window_x11_)
|
|
|
|
return view;
|
|
|
|
|
|
|
|
// We can't use aura::Window::GetBoundsInScreen on Linux because it will
|
2020-08-29 00:39:23 +02:00
|
|
|
// return bounds from DesktopWindowTreeHostLinux which in our case is relative
|
2015-11-17 19:20:13 +01:00
|
|
|
// to the parent window instead of the root window (screen).
|
|
|
|
const gfx::Rect& bounds_in_screen = window_x11_->GetBoundsInScreen();
|
|
|
|
return gfx::Point(bounds_in_screen.x() + view.x(),
|
|
|
|
bounds_in_screen.y() + view.y());
|
2019-04-23 19:00:14 +02:00
|
|
|
#endif // defined(USE_X11)
|
|
|
|
return gfx::Point();
|
2015-11-17 19:20:13 +01:00
|
|
|
}
|
2014-05-22 23:01:22 +02:00
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
void CefBrowserPlatformDelegateNativeLinux::ViewText(const std::string& text) {
|
2014-05-22 23:01:22 +02:00
|
|
|
char buff[] = "/tmp/CEFSourceXXXXXX";
|
|
|
|
int fd = mkstemp(buff);
|
|
|
|
|
|
|
|
if (fd == -1)
|
2015-11-17 19:20:13 +01:00
|
|
|
return;
|
2014-05-22 23:01:22 +02:00
|
|
|
|
|
|
|
FILE* srcOutput = fdopen(fd, "w+");
|
|
|
|
if (!srcOutput)
|
2015-11-17 19:20:13 +01:00
|
|
|
return;
|
2014-05-22 23:01:22 +02:00
|
|
|
|
|
|
|
if (fputs(text.c_str(), srcOutput) < 0) {
|
|
|
|
fclose(srcOutput);
|
2015-11-17 19:20:13 +01:00
|
|
|
return;
|
2014-05-22 23:01:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(srcOutput);
|
|
|
|
|
|
|
|
std::string newName(buff);
|
|
|
|
newName.append(".txt");
|
|
|
|
if (rename(buff, newName.c_str()) != 0)
|
2015-11-17 19:20:13 +01:00
|
|
|
return;
|
2014-05-22 23:01:22 +02:00
|
|
|
|
|
|
|
std::string openCommand("xdg-open ");
|
|
|
|
openCommand += newName;
|
|
|
|
|
2016-06-03 17:33:06 +02:00
|
|
|
int result = system(openCommand.c_str());
|
|
|
|
ALLOW_UNUSED_LOCAL(result);
|
2014-05-22 23:01:22 +02:00
|
|
|
}
|
|
|
|
|
2018-11-03 02:15:09 +01:00
|
|
|
bool CefBrowserPlatformDelegateNativeLinux::HandleKeyboardEvent(
|
2014-05-22 23:01:22 +02:00
|
|
|
const content::NativeWebKeyboardEvent& event) {
|
|
|
|
// TODO(cef): Is something required here to handle shortcut keys?
|
2018-11-03 02:15:09 +01:00
|
|
|
return false;
|
2014-05-22 23:01:22 +02:00
|
|
|
}
|
|
|
|
|
2019-04-24 04:50:25 +02:00
|
|
|
// static
|
|
|
|
void CefBrowserPlatformDelegate::HandleExternalProtocol(const GURL& url) {}
|
2014-05-22 23:01:22 +02:00
|
|
|
|
2015-11-17 19:20:13 +01:00
|
|
|
CefEventHandle CefBrowserPlatformDelegateNativeLinux::GetEventHandle(
|
|
|
|
const content::NativeWebKeyboardEvent& event) const {
|
2020-03-30 22:13:42 +02:00
|
|
|
// TODO(cef): We need to return an XEvent* from this method, but
|
|
|
|
// |event.os_event->native_event()| now returns a ui::Event* instead.
|
|
|
|
// See https://crbug.com/965991.
|
|
|
|
return nullptr;
|
2015-11-17 19:20:13 +01:00
|
|
|
}
|
|
|
|
|
2016-04-27 22:38:52 +02:00
|
|
|
std::unique_ptr<CefMenuRunner>
|
2017-05-17 11:29:28 +02:00
|
|
|
CefBrowserPlatformDelegateNativeLinux::CreateMenuRunner() {
|
2016-05-25 01:35:43 +02:00
|
|
|
return base::WrapUnique(new CefMenuRunnerLinux);
|
2015-11-17 19:20:13 +01:00
|
|
|
}
|
|
|
|
|
2019-07-17 20:47:27 +02:00
|
|
|
gfx::Point CefBrowserPlatformDelegateNativeLinux::GetDialogPosition(
|
|
|
|
const gfx::Size& size) {
|
|
|
|
const gfx::Size& max_size = GetMaximumDialogSize();
|
|
|
|
return gfx::Point((max_size.width() - size.width()) / 2,
|
|
|
|
(max_size.height() - size.height()) / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::Size CefBrowserPlatformDelegateNativeLinux::GetMaximumDialogSize() {
|
|
|
|
return GetWindowWidget()->GetWindowBoundsInScreen().size();
|
2019-11-12 17:11:44 +01:00
|
|
|
}
|
2020-01-23 22:58:01 +01:00
|
|
|
|
|
|
|
ui::KeyEvent CefBrowserPlatformDelegateNativeLinux::TranslateUiKeyEvent(
|
|
|
|
const CefKeyEvent& key_event) const {
|
|
|
|
int flags = TranslateUiEventModifiers(key_event.modifiers);
|
|
|
|
ui::KeyboardCode key_code =
|
|
|
|
static_cast<ui::KeyboardCode>(key_event.windows_key_code);
|
|
|
|
ui::DomCode dom_code =
|
|
|
|
ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.native_key_code);
|
|
|
|
int keysym = ui::XKeysymForWindowsKeyCode(
|
|
|
|
key_code, !!(key_event.modifiers & EVENTFLAG_SHIFT_DOWN));
|
2021-04-21 00:52:34 +02:00
|
|
|
char16_t character = ui::GetUnicodeCharacterFromXKeySym(keysym);
|
2020-01-23 22:58:01 +01:00
|
|
|
base::TimeTicks time_stamp = GetEventTimeStamp();
|
|
|
|
|
|
|
|
if (key_event.type == KEYEVENT_CHAR) {
|
|
|
|
return ui::KeyEvent(character, key_code, dom_code, flags, time_stamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
ui::EventType type = ui::ET_UNKNOWN;
|
|
|
|
switch (key_event.type) {
|
|
|
|
case KEYEVENT_RAWKEYDOWN:
|
|
|
|
case KEYEVENT_KEYDOWN:
|
|
|
|
type = ui::ET_KEY_PRESSED;
|
|
|
|
break;
|
|
|
|
case KEYEVENT_KEYUP:
|
|
|
|
type = ui::ET_KEY_RELEASED;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NOTREACHED();
|
|
|
|
}
|
|
|
|
|
|
|
|
ui::DomKey dom_key = ui::XKeySymToDomKey(keysym, character);
|
|
|
|
return ui::KeyEvent(type, key_code, dom_code, flags, dom_key, time_stamp);
|
|
|
|
}
|
|
|
|
|
2020-04-08 17:43:39 +02:00
|
|
|
content::NativeWebKeyboardEvent
|
|
|
|
CefBrowserPlatformDelegateNativeLinux::TranslateWebKeyEvent(
|
|
|
|
const CefKeyEvent& key_event) const {
|
|
|
|
ui::KeyEvent ui_event = TranslateUiKeyEvent(key_event);
|
|
|
|
if (key_event.type == KEYEVENT_CHAR) {
|
|
|
|
return content::NativeWebKeyboardEvent(ui_event, key_event.character);
|
|
|
|
}
|
|
|
|
return content::NativeWebKeyboardEvent(ui_event);
|
|
|
|
}
|