Linux: cefclient: Port to GTK3 (see issue #2969)
GTK3 is required by the Chrome runtime. The cefclient off-screen rendering example no longer works with Ubuntu 16.04. With end-of-life in April 2021 we are dropping support for 16.04 in the near future in any case.
This commit is contained in:
parent
8424f166cc
commit
020ac1b509
12
BUILD.gn
12
BUILD.gn
|
@ -2035,18 +2035,12 @@ if (is_mac) {
|
|||
pkg_config("gtk") {
|
||||
packages = [
|
||||
"gmodule-2.0",
|
||||
"gtk+-2.0",
|
||||
"gtk+-3.0",
|
||||
"gthread-2.0",
|
||||
"gtk+-unix-print-2.0",
|
||||
"gtk+-unix-print-3.0",
|
||||
"xi",
|
||||
]
|
||||
}
|
||||
|
||||
pkg_config("gtkglext") {
|
||||
packages = [
|
||||
"gtkglext-1.0",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
|
@ -2127,13 +2121,13 @@ if (is_mac) {
|
|||
]
|
||||
|
||||
libs = [
|
||||
"GL",
|
||||
"X11",
|
||||
]
|
||||
|
||||
if (cef_use_gtk) {
|
||||
configs += [
|
||||
":gtk",
|
||||
":gtkglext",
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -44,8 +44,7 @@
|
|||
# work but may not have been tested.
|
||||
# Required packages include:
|
||||
# build-essential
|
||||
# libgtk2.0-dev (required by the cefclient target only)
|
||||
# libgtkglext1-dev (required by the cefclient target only)
|
||||
# libgtk3.0-dev (required by the cefclient target only)
|
||||
#
|
||||
# - MacOS requirements:
|
||||
# Xcode 8 or newer building on MacOS 10.11 (El Capitan) or newer for x86_64.
|
||||
|
|
|
@ -95,6 +95,7 @@ if(OS_LINUX)
|
|||
-Wno-unused-parameter # Don't warn about unused parameters
|
||||
-Wno-error=comment # Don't warn about code in comments
|
||||
-Wno-comment # Don't warn about code in comments
|
||||
-Wno-deprecated-declarations # Don't warn about using deprecated methods
|
||||
)
|
||||
list(APPEND CEF_C_COMPILER_FLAGS
|
||||
-std=c99 # Use the C99 language standard
|
||||
|
|
|
@ -122,13 +122,13 @@ if(OS_LINUX)
|
|||
)
|
||||
|
||||
# Find required libraries and update compiler/linker variables.
|
||||
FIND_LINUX_LIBRARIES("gmodule-2.0 gtk+-2.0 gthread-2.0 gtk+-unix-print-2.0 gtkglext-1.0 xi")
|
||||
FIND_LINUX_LIBRARIES("gmodule-2.0 gtk+-3.0 gthread-2.0 gtk+-unix-print-3.0 xi")
|
||||
|
||||
# Executable target.
|
||||
add_executable(${CEF_TARGET} ${CEFCLIENT_SRCS})
|
||||
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
|
||||
add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
|
||||
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
|
||||
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper "GL" ${CEF_STANDARD_LIBS})
|
||||
|
||||
# Set rpath so that libraries can be placed next to the executable.
|
||||
set_target_properties(${CEF_TARGET} PROPERTIES INSTALL_RPATH "$ORIGIN")
|
||||
|
|
|
@ -6,16 +6,14 @@
|
|||
|
||||
#include <GL/gl.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gdk/gdkkeysyms-compat.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <glib-object.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtk/gtkgl.h>
|
||||
|
||||
#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"
|
||||
|
@ -29,17 +27,10 @@ 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)
|
||||
|
@ -59,20 +50,6 @@ 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,
|
||||
|
@ -894,17 +871,20 @@ void GetWidgetRectInScreen(GtkWidget* widget, GdkRectangle* r) {
|
|||
// 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);
|
||||
w = gdk_window_get_width(window);
|
||||
h = gdk_window_get_height(window);
|
||||
// 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;
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(widget, &allocation);
|
||||
r->x = x + border + allocation.x;
|
||||
r->y = y + (extents.height - h) - border + allocation.y;
|
||||
r->width = allocation.width;
|
||||
r->height = allocation.height;
|
||||
}
|
||||
|
||||
CefBrowserHost::DragOperationsMask GetDragOperationsMask(
|
||||
|
@ -925,30 +905,25 @@ CefBrowserHost::DragOperationsMask GetDragOperationsMask(
|
|||
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);
|
||||
: swap_buffers_(swap_buffers), widget_(widget) {
|
||||
gtk_gl_area_make_current(GTK_GL_AREA(widget));
|
||||
is_valid_ = gtk_gl_area_get_error(GTK_GL_AREA(widget)) == NULL;
|
||||
if (swap_buffers_ && is_valid_) {
|
||||
gtk_gl_area_queue_render(GTK_GL_AREA(widget_));
|
||||
gtk_gl_area_attach_buffers(GTK_GL_AREA(widget));
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
if (swap_buffers_ && is_valid_)
|
||||
glFlush();
|
||||
}
|
||||
|
||||
bool IsValid() const { return is_valid_; }
|
||||
|
||||
private:
|
||||
bool swap_buffers_;
|
||||
GdkGLDrawable* gldrawable_;
|
||||
GtkWidget* const widget_;
|
||||
bool is_valid_;
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads_;
|
||||
};
|
||||
|
@ -1013,11 +988,11 @@ void BrowserWindowOsrGtk::CreateBrowser(
|
|||
// Retrieve the X11 Window ID for the GTK parent window.
|
||||
GtkWidget* window =
|
||||
gtk_widget_get_ancestor(GTK_WIDGET(parent_handle), GTK_TYPE_WINDOW);
|
||||
::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(window));
|
||||
DCHECK(xwindow);
|
||||
CefWindowHandle handle = GDK_WINDOW_XID(gtk_widget_get_window(window));
|
||||
DCHECK(handle);
|
||||
|
||||
CefWindowInfo window_info;
|
||||
window_info.SetAsWindowless(xwindow);
|
||||
window_info.SetAsWindowless(handle);
|
||||
|
||||
// Create the browser asynchronously.
|
||||
CefBrowserHost::CreateBrowser(window_info, client_handler_,
|
||||
|
@ -1172,11 +1147,12 @@ void BrowserWindowOsrGtk::GetViewRect(CefRefPtr<CefBrowser> browser,
|
|||
|
||||
// The simulated screen and view rectangle are the same. This is necessary
|
||||
// for popup menus to be located and sized inside the view.
|
||||
rect.width = DeviceToLogical(glarea_->allocation.width, device_scale_factor);
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(glarea_, &allocation);
|
||||
rect.width = DeviceToLogical(allocation.width, device_scale_factor);
|
||||
if (rect.width == 0)
|
||||
rect.width = 1;
|
||||
rect.height =
|
||||
DeviceToLogical(glarea_->allocation.height, device_scale_factor);
|
||||
rect.height = DeviceToLogical(allocation.height, device_scale_factor);
|
||||
if (rect.height == 0)
|
||||
rect.height = 1;
|
||||
}
|
||||
|
@ -1373,18 +1349,13 @@ void BrowserWindowOsrGtk::Create(ClientWindowHandle parent_handle) {
|
|||
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
glarea_ = gtk_drawing_area_new();
|
||||
glarea_ = gtk_gl_area_new();
|
||||
DCHECK(glarea_);
|
||||
|
||||
GdkGLConfig* glconfig =
|
||||
gdk_gl_config_new_by_mode(static_cast<GdkGLConfigMode>(
|
||||
GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
|
||||
DCHECK(glconfig);
|
||||
|
||||
gtk_widget_set_gl_capability(glarea_, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
|
||||
|
||||
gtk_widget_set_can_focus(glarea_, TRUE);
|
||||
|
||||
gtk_gl_area_set_auto_render(GTK_GL_AREA(glarea_), FALSE);
|
||||
|
||||
g_signal_connect(G_OBJECT(glarea_), "size_allocate",
|
||||
G_CALLBACK(&BrowserWindowOsrGtk::SizeAllocation), this);
|
||||
|
||||
|
@ -1414,18 +1385,16 @@ void BrowserWindowOsrGtk::Create(ClientWindowHandle parent_handle) {
|
|||
G_CALLBACK(&BrowserWindowOsrGtk::FocusEvent), this);
|
||||
g_signal_connect(G_OBJECT(glarea_), "focus_out_event",
|
||||
G_CALLBACK(&BrowserWindowOsrGtk::FocusEvent), this);
|
||||
g_signal_connect(G_OBJECT(glarea_), "touch-event",
|
||||
G_CALLBACK(&BrowserWindowOsrGtk::TouchEvent), this);
|
||||
|
||||
RegisterDragDrop();
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(parent_handle), glarea_);
|
||||
gtk_widget_set_vexpand(glarea_, TRUE);
|
||||
gtk_grid_attach(GTK_GRID(parent_handle), glarea_, 0, 3, 1, 1);
|
||||
|
||||
// Make the GlArea visible in the parent container.
|
||||
gtk_widget_show_all(parent_handle);
|
||||
|
||||
InitializeXinput(xdisplay_);
|
||||
|
||||
if (IsTouchAvailable())
|
||||
RegisterTouch();
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -1661,6 +1630,9 @@ gint BrowserWindowOsrGtk::ScrollEvent(GtkWidget* widget,
|
|||
case GDK_SCROLL_RIGHT:
|
||||
deltaX = -scrollbarPixelsPerGtkTick;
|
||||
break;
|
||||
case GDK_SCROLL_SMOOTH:
|
||||
NOTIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
|
||||
host->SendMouseWheelEvent(mouse_event, deltaX, deltaY);
|
||||
|
@ -1677,106 +1649,49 @@ gint BrowserWindowOsrGtk::FocusEvent(GtkWidget* widget,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void BrowserWindowOsrGtk::TouchEvent(CefXIDeviceEvent event) {
|
||||
if (!browser_.get())
|
||||
return;
|
||||
// static
|
||||
gboolean BrowserWindowOsrGtk::TouchEvent(GtkWidget* widget,
|
||||
GdkEventTouch* event,
|
||||
BrowserWindowOsrGtk* self) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
XIDeviceEvent* ev = static_cast<XIDeviceEvent*>(event);
|
||||
CefTouchEvent cef_event;
|
||||
switch (ev->evtype) {
|
||||
case XI_TouchBegin:
|
||||
cef_event.type = CEF_TET_PRESSED;
|
||||
if (!self->browser_.get())
|
||||
return TRUE;
|
||||
|
||||
CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
|
||||
|
||||
float device_scale_factor;
|
||||
{
|
||||
base::AutoLock lock_scope(self->lock_);
|
||||
device_scale_factor = self->device_scale_factor_;
|
||||
}
|
||||
|
||||
CefTouchEvent touch_event;
|
||||
switch (event->type) {
|
||||
case GDK_TOUCH_BEGIN:
|
||||
touch_event.type = CEF_TET_PRESSED;
|
||||
break;
|
||||
case XI_TouchUpdate:
|
||||
cef_event.type = CEF_TET_MOVED;
|
||||
case GDK_TOUCH_UPDATE:
|
||||
touch_event.type = CEF_TET_MOVED;
|
||||
break;
|
||||
case XI_TouchEnd:
|
||||
cef_event.type = CEF_TET_RELEASED;
|
||||
case GDK_TOUCH_END:
|
||||
touch_event.type = CEF_TET_RELEASED;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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);
|
||||
touch_event.x = event->x;
|
||||
touch_event.y = event->y;
|
||||
touch_event.radius_x = 0;
|
||||
touch_event.radius_y = 0;
|
||||
touch_event.rotation_angle = 0;
|
||||
touch_event.pressure = 0;
|
||||
DeviceToLogical(touch_event, device_scale_factor);
|
||||
touch_event.modifiers = GetCefStateModifiers(event->state);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
host->SendTouchEvent(touch_event);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool BrowserWindowOsrGtk::IsOverPopupWidget(int x, int y) const {
|
||||
|
|
|
@ -117,8 +117,10 @@ class BrowserWindowOsrGtk : public BrowserWindow,
|
|||
static gint FocusEvent(GtkWidget* widget,
|
||||
GdkEventFocus* event,
|
||||
BrowserWindowOsrGtk* self);
|
||||
static gboolean TouchEvent(GtkWidget* widget,
|
||||
GdkEventTouch* event,
|
||||
BrowserWindowOsrGtk* self);
|
||||
|
||||
void TouchEvent(CefXIDeviceEvent event);
|
||||
void RegisterTouch();
|
||||
|
||||
bool IsOverPopupWidget(int x, int y) const;
|
||||
|
@ -176,7 +178,6 @@ class BrowserWindowOsrGtk : public BrowserWindow,
|
|||
static GdkFilterReturn EventFilter(GdkXEvent* gdk_xevent,
|
||||
GdkEvent* event,
|
||||
gpointer data);
|
||||
static void InitializeXinput(XDisplay* xdisplay);
|
||||
|
||||
XDisplay* xdisplay_;
|
||||
|
||||
|
|
|
@ -135,10 +135,10 @@ GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
|
|||
scoped_refptr<RootWindow> root_window =
|
||||
RootWindow::GetForBrowser(browser->GetIdentifier());
|
||||
if (root_window) {
|
||||
GtkWindow* window = GTK_WINDOW(root_window->GetWindowHandle());
|
||||
GtkWidget* window = root_window->GetWindowHandle();
|
||||
if (!window)
|
||||
LOG(ERROR) << "No GtkWindow for browser";
|
||||
return window;
|
||||
return GTK_WINDOW(window);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -238,13 +238,13 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
|||
|
||||
if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
accept_button = GTK_STOCK_OPEN;
|
||||
accept_button = "_Open";
|
||||
} else if (mode_type == FILE_DIALOG_OPEN_FOLDER) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
accept_button = GTK_STOCK_OPEN;
|
||||
accept_button = "_Open";
|
||||
} else if (mode_type == FILE_DIALOG_SAVE) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_SAVE;
|
||||
accept_button = GTK_STOCK_SAVE;
|
||||
accept_button = "_Save";
|
||||
} else {
|
||||
NOTREACHED();
|
||||
params.callback->Cancel();
|
||||
|
@ -274,7 +274,7 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
|||
}
|
||||
|
||||
GtkWidget* dialog = gtk_file_chooser_dialog_new(
|
||||
title_str.c_str(), GTK_WINDOW(window), action, GTK_STOCK_CANCEL,
|
||||
title_str.c_str(), GTK_WINDOW(window), action, "_Cancel",
|
||||
GTK_RESPONSE_CANCEL, accept_button, GTK_RESPONSE_ACCEPT, NULL);
|
||||
|
||||
if (mode_type == FILE_DIALOG_OPEN_MULTIPLE)
|
||||
|
@ -406,8 +406,8 @@ void ClientDialogHandlerGtk::OnJSDialogContinue(OnJSDialogParams params,
|
|||
|
||||
gtk_window_set_title(GTK_WINDOW(gtk_dialog_), title.c_str());
|
||||
|
||||
GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_),
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK);
|
||||
GtkWidget* ok_button =
|
||||
gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), "_OK", GTK_RESPONSE_OK);
|
||||
|
||||
if (params.dialog_type != JSDIALOGTYPE_PROMPT)
|
||||
gtk_widget_grab_focus(ok_button);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "tests/cefclient/browser/main_message_loop_multithreaded_gtk.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <gtk/gtkmain.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/base/cef_logging.h"
|
||||
|
|
|
@ -539,7 +539,7 @@ struct ClientPrintHandlerGtk::PrintHandler {
|
|||
}
|
||||
}
|
||||
|
||||
void OnJobCompleted(GtkPrintJob* print_job, GError* error) {
|
||||
void OnJobCompleted(GtkPrintJob* print_job, const GError* error) {
|
||||
// Continue() will result in a call to ClientPrintHandlerGtk::OnPrintReset
|
||||
// which deletes |this|. Execute it asnychronously so the call stack has a
|
||||
// chance to unwind.
|
||||
|
@ -556,7 +556,7 @@ struct ClientPrintHandlerGtk::PrintHandler {
|
|||
|
||||
static void OnJobCompletedThunk(GtkPrintJob* print_job,
|
||||
void* handler,
|
||||
GError* error) {
|
||||
const GError* error) {
|
||||
static_cast<PrintHandler*>(handler)->OnJobCompleted(print_job, error);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,36 @@ namespace {
|
|||
|
||||
const char kMenuIdKey[] = "menu_id";
|
||||
|
||||
void UseDefaultX11VisualForGtk(GtkWidget* widget) {
|
||||
#if GTK_CHECK_VERSION(3, 15, 1)
|
||||
// GTK+ > 3.15.1 uses an X11 visual optimized for GTK+'s OpenGL stuff
|
||||
// since revid dae447728d: https://github.com/GNOME/gtk/commit/dae447728d
|
||||
// However, it breaks CEF: https://github.com/cztomczak/cefcapi/issues/9
|
||||
// Let's use the default X11 visual instead of the GTK's blessed one.
|
||||
// Copied from: https://github.com/cztomczak/cefcapi.
|
||||
GdkScreen* screen = gdk_screen_get_default();
|
||||
GList* visuals = gdk_screen_list_visuals(screen);
|
||||
|
||||
GdkX11Screen* x11_screen = GDK_X11_SCREEN(screen);
|
||||
if (x11_screen == NULL)
|
||||
return;
|
||||
|
||||
Visual* default_xvisual = DefaultVisual(GDK_SCREEN_XDISPLAY(x11_screen),
|
||||
GDK_SCREEN_XNUMBER(x11_screen));
|
||||
GList* cursor = visuals;
|
||||
while (cursor != NULL) {
|
||||
GdkVisual* visual = GDK_X11_VISUAL(cursor->data);
|
||||
if (default_xvisual->visualid ==
|
||||
gdk_x11_visual_get_xvisual(visual)->visualid) {
|
||||
gtk_widget_set_visual(widget, visual);
|
||||
break;
|
||||
}
|
||||
cursor = cursor->next;
|
||||
}
|
||||
g_list_free(visuals);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsWindowMaximized(GtkWindow* window) {
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
||||
gint state = gdk_window_get_state(gdk_window);
|
||||
|
@ -143,6 +173,7 @@ void RootWindowGtk::Show(ShowMode mode) {
|
|||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
// Show the GTK window.
|
||||
UseDefaultX11VisualForGtk(GTK_WIDGET(window_));
|
||||
gtk_widget_show_all(window_);
|
||||
|
||||
if (mode == ShowMinimized)
|
||||
|
@ -290,23 +321,34 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
|
|||
G_CALLBACK(&RootWindowGtk::WindowDelete), this);
|
||||
|
||||
const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
|
||||
GdkColor color = {0};
|
||||
color.red = CefColorGetR(background_color) * 65535 / 255;
|
||||
color.green = CefColorGetG(background_color) * 65535 / 255;
|
||||
color.blue = CefColorGetB(background_color) * 65535 / 255;
|
||||
gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &color);
|
||||
GdkRGBA rgba = {0};
|
||||
rgba.red = CefColorGetR(background_color) * 65535 / 255;
|
||||
rgba.green = CefColorGetG(background_color) * 65535 / 255;
|
||||
rgba.blue = CefColorGetB(background_color) * 65535 / 255;
|
||||
rgba.alpha = 1;
|
||||
|
||||
GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
|
||||
g_signal_connect(vbox, "size-allocate",
|
||||
G_CALLBACK(&RootWindowGtk::VboxSizeAllocated), this);
|
||||
gtk_container_add(GTK_CONTAINER(window_), vbox);
|
||||
gchar* css = g_strdup_printf("#* { background-color: %s; }",
|
||||
gdk_rgba_to_string(&rgba));
|
||||
GtkCssProvider* provider = gtk_css_provider_new();
|
||||
gtk_css_provider_load_from_data(provider, css, -1, nullptr);
|
||||
g_free(css);
|
||||
gtk_style_context_add_provider(gtk_widget_get_style_context(window_),
|
||||
GTK_STYLE_PROVIDER(provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_object_unref(provider);
|
||||
|
||||
GtkWidget* grid = gtk_grid_new();
|
||||
gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
|
||||
g_signal_connect(grid, "size-allocate",
|
||||
G_CALLBACK(&RootWindowGtk::GridSizeAllocated), this);
|
||||
gtk_container_add(GTK_CONTAINER(window_), grid);
|
||||
|
||||
if (with_controls_) {
|
||||
GtkWidget* menu_bar = CreateMenuBar();
|
||||
g_signal_connect(menu_bar, "size-allocate",
|
||||
G_CALLBACK(&RootWindowGtk::MenubarSizeAllocated), this);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 0);
|
||||
gtk_grid_attach(GTK_GRID(grid), menu_bar, 0, 0, 1, 1);
|
||||
|
||||
GtkWidget* toolbar = gtk_toolbar_new();
|
||||
// Turn off the labels on the toolbar buttons.
|
||||
|
@ -314,22 +356,26 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
|
|||
g_signal_connect(toolbar, "size-allocate",
|
||||
G_CALLBACK(&RootWindowGtk::ToolbarSizeAllocated), this);
|
||||
|
||||
back_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
|
||||
back_button_ = gtk_tool_button_new(
|
||||
gtk_image_new_from_icon_name("go-previous", GTK_ICON_SIZE_MENU), NULL);
|
||||
g_signal_connect(back_button_, "clicked",
|
||||
G_CALLBACK(&RootWindowGtk::BackButtonClicked), this);
|
||||
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), back_button_, -1 /* append */);
|
||||
|
||||
forward_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
|
||||
forward_button_ = gtk_tool_button_new(
|
||||
gtk_image_new_from_icon_name("go-next", GTK_ICON_SIZE_MENU), NULL);
|
||||
g_signal_connect(forward_button_, "clicked",
|
||||
G_CALLBACK(&RootWindowGtk::ForwardButtonClicked), this);
|
||||
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), forward_button_, -1 /* append */);
|
||||
|
||||
reload_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH);
|
||||
reload_button_ = gtk_tool_button_new(
|
||||
gtk_image_new_from_icon_name("view-refresh", GTK_ICON_SIZE_MENU), NULL);
|
||||
g_signal_connect(reload_button_, "clicked",
|
||||
G_CALLBACK(&RootWindowGtk::ReloadButtonClicked), this);
|
||||
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), reload_button_, -1 /* append */);
|
||||
|
||||
stop_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_STOP);
|
||||
stop_button_ = gtk_tool_button_new(
|
||||
gtk_image_new_from_icon_name("process-stop", GTK_ICON_SIZE_MENU), NULL);
|
||||
g_signal_connect(stop_button_, "clicked",
|
||||
G_CALLBACK(&RootWindowGtk::StopButtonClicked), this);
|
||||
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), stop_button_, -1 /* append */);
|
||||
|
@ -345,7 +391,8 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
|
|||
gtk_tool_item_set_expand(tool_item, TRUE);
|
||||
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1); // append
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
|
||||
gtk_grid_attach_next_to(GTK_GRID(grid), toolbar, menu_bar, GTK_POS_BOTTOM,
|
||||
1, 1);
|
||||
}
|
||||
|
||||
// Realize (show) the GTK widget. This must be done before the browser is
|
||||
|
@ -360,8 +407,8 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
|
|||
|
||||
// Windowed browsers are parented to the X11 Window underlying the GtkWindow*
|
||||
// and must be sized manually. The OSR GTK widget, on the other hand, can be
|
||||
// added to the Vbox container for automatic layout-based sizing.
|
||||
GtkWidget* parent = with_osr_ ? vbox : window_;
|
||||
// added to the grid container for automatic layout-based sizing.
|
||||
GtkWidget* parent = with_osr_ ? grid : window_;
|
||||
|
||||
// Set the Display associated with the browser.
|
||||
::Display* xdisplay = GDK_WINDOW_XDISPLAY(gtk_widget_get_window(window_));
|
||||
|
@ -746,7 +793,7 @@ gboolean RootWindowGtk::WindowDelete(GtkWidget* widget,
|
|||
}
|
||||
|
||||
// static
|
||||
void RootWindowGtk::VboxSizeAllocated(GtkWidget* widget,
|
||||
void RootWindowGtk::GridSizeAllocated(GtkWidget* widget,
|
||||
GtkAllocation* allocation,
|
||||
RootWindowGtk* self) {
|
||||
// May be called on the main thread and the UI thread.
|
||||
|
|
|
@ -97,7 +97,7 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
|
|||
RootWindowGtk* self);
|
||||
|
||||
// Signal handlers for the GTK Vbox containing all UX elements.
|
||||
static void VboxSizeAllocated(GtkWidget* widget,
|
||||
static void GridSizeAllocated(GtkWidget* widget,
|
||||
GtkAllocation* allocation,
|
||||
RootWindowGtk* self);
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// can be found in the LICENSE file.
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtk/gtkgl.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#undef Success // Definition conflicts with cef_message_router.h
|
||||
|
@ -98,6 +97,13 @@ int RunMain(int argc, char* argv[]) {
|
|||
// Populate the settings based on command line arguments.
|
||||
context->PopulateSettings(&settings);
|
||||
|
||||
if (settings.windowless_rendering_enabled) {
|
||||
// Force the app to use OpenGL <= 3.1 when off-screen rendering is enabled.
|
||||
// TODO(cefclient): Rewrite OSRRenderer to use shaders instead of the
|
||||
// fixed-function pipeline which was removed in OpenGL 3.2 (back in 2009).
|
||||
setenv("MESA_GL_VERSION_OVERRIDE", "3.1", /*overwrite=*/0);
|
||||
}
|
||||
|
||||
// Create the main message loop object.
|
||||
scoped_ptr<MainMessageLoop> message_loop;
|
||||
if (settings.multi_threaded_message_loop)
|
||||
|
@ -110,13 +116,13 @@ int RunMain(int argc, char* argv[]) {
|
|||
// Initialize CEF.
|
||||
context->Initialize(main_args, settings, app, nullptr);
|
||||
|
||||
// Force Gtk to use Xwayland (in case a Wayland compositor is being used).
|
||||
gdk_set_allowed_backends("x11");
|
||||
|
||||
// The Chromium sandbox requires that there only be a single thread during
|
||||
// initialization. Therefore initialize GTK after CEF.
|
||||
gtk_init(&argc, &argv_copy);
|
||||
|
||||
// Perform gtkglext initialization required by the OSR example.
|
||||
gtk_gl_init(&argc, &argv_copy);
|
||||
|
||||
// Install xlib error handlers so that the application won't be terminated
|
||||
// on non-fatal errors. Must be done after initializing GTK.
|
||||
XSetErrorHandler(XErrorHandlerImpl);
|
||||
|
|
|
@ -30,4 +30,9 @@ void DeviceToLogical(CefMouseEvent& value, float device_scale_factor) {
|
|||
value.y = DeviceToLogical(value.y, device_scale_factor);
|
||||
}
|
||||
|
||||
void DeviceToLogical(CefTouchEvent& value, float device_scale_factor) {
|
||||
value.x = DeviceToLogical(value.x, device_scale_factor);
|
||||
value.y = DeviceToLogical(value.y, device_scale_factor);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
|
|
@ -17,6 +17,7 @@ CefRect LogicalToDevice(const CefRect& value, float device_scale_factor);
|
|||
// Convert |value| from device coordinates to logical coordinates.
|
||||
int DeviceToLogical(int value, float device_scale_factor);
|
||||
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor);
|
||||
void DeviceToLogical(CefTouchEvent& value, float device_scale_factor);
|
||||
|
||||
} // namespace client
|
||||
|
||||
|
|
Loading…
Reference in New Issue