forked from cztomczak/cefpython
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathx11.cpp
More file actions
165 lines (156 loc) · 6.56 KB
/
Copy pathx11.cpp
File metadata and controls
165 lines (156 loc) · 6.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright (c) 2016 CEF Python, see the Authors file.
// All rights reserved. Licensed under BSD 3-clause license.
// Project website: https://github.com/cztomczak/cefpython
// NOTE: This file is also used by "subprocess" and "libcefpythonapp"
// targets during build.
#include "x11.h"
#include "util.h"
#include "include/base/cef_logging.h"
int XErrorHandlerImpl(Display *display, XErrorEvent *event) {
LOG(INFO) << "[Browser process] "
<< "X error received: "
<< "type " << event->type << ", "
<< "serial " << event->serial << ", "
<< "error_code " << static_cast<int>(event->error_code) << ", "
<< "request_code " << static_cast<int>(event->request_code) << ", "
<< "minor_code " << static_cast<int>(event->minor_code);
return 0;
}
int XIOErrorHandlerImpl(Display *display) {
return 0;
}
void InstallX11ErrorHandlers() {
// Copied from upstream cefclient.
// Install xlib error handlers so that the application won't be terminated
// on non-fatal errors. Must be done after initializing GTK.
LOG(INFO) << "[Browser process] Install X11 error handlers";
XSetErrorHandler(XErrorHandlerImpl);
XSetIOErrorHandler(XIOErrorHandlerImpl);
}
void SetX11WindowBounds(CefRefPtr<CefBrowser> browser,
int x, int y, int width, int height) {
REQUIRE_UI_THREAD();
// xwindow is 0 for windowless (OSR) browsers - nothing to resize, and no
// need to touch X11 at all, so check this first.
::Window xwindow = browser->GetHost()->GetWindowHandle();
if (!xwindow) return;
// cef_get_xdisplay() is NULL off the UI thread (cef_types_linux.h; the
// assert above is compiled out in release builds) and on any thread when
// the app selects a non-X11 Ozone backend with no X server.
// XConfigureWindow(NULL, ...) segfaults (verified), so no-op instead.
::Display* xdisplay = cef_get_xdisplay();
if (!xdisplay) {
LOG(INFO) << "[Browser process] SetX11WindowBounds: no X11 display "
"(wrong thread or non-X11 backend), skipping";
return;
}
XWindowChanges changes = {0};
changes.x = x;
changes.y = y;
changes.width = static_cast<int>(width);
changes.height = static_cast<int>(height);
XConfigureWindow(xdisplay, xwindow,
CWX | CWY | CWHeight | CWWidth, &changes);
XFlush(xdisplay);
}
void SetX11WindowTitle(CefRefPtr<CefBrowser> browser, char* title) {
REQUIRE_UI_THREAD();
// xwindow is 0 for windowless (OSR) browsers - no title bar to set.
::Window xwindow = browser->GetHost()->GetWindowHandle();
if (!xwindow) return;
// See SetX11WindowBounds: NULL off the UI thread or on a non-X11 Ozone
// backend; XStoreName(NULL, ...) would segfault.
::Display* xdisplay = cef_get_xdisplay();
if (!xdisplay) {
LOG(INFO) << "[Browser process] SetX11WindowTitle: no X11 display "
"(wrong thread or non-X11 backend), skipping";
return;
}
XStoreName(xdisplay, xwindow, title);
}
GtkWindow* CefBrowser_GetGtkWindow(CefRefPtr<CefBrowser> browser) {
// TODO: Should return NULL when using the Views framework
// -- REWRITTEN FOR CEF PYTHON USE CASE --
//
// Returns a GtkWindow* to use as the transient parent for GTK dialogs (the
// file-chooser and print handlers); it is never used for browser embedding.
//
// Upstream cefclient gets this parent from its own top-level GtkWindow, via
// RootWindow::GetForBrowser(id)->GetWindowHandle() - see GetWindow() in CEF's
// tests/cefclient/browser/dialog_handler_gtk.cc. cefpython has no such
// GtkWindow: the browser is embedded with CefWindowInfo::SetAsChild() into a
// foreign toolkit's X11 window (Qt/GTK/wx/tk), not a cefclient RootWindow.
// So instead we wrap the browser's own X11 window - CefBrowserHost::
// GetWindowHandle(), which is the XID on Linux (include/cef_browser.h) - as a
// GtkWindow using gtk_plug_new_for_display().
//
// The browser window is not a real GtkSocket, so GTK may log
// "Can't create GtkPlug as child of non-GtkSocket" (harmless; the dialog
// still works - see the note further down).
//
// X11 window handle
::Window xwindow = browser->GetHost()->GetWindowHandle();
// X11 display
::Display* xdisplay = cef_get_xdisplay();
// GDK display
GdkDisplay* gdk_display = NULL;
if (xdisplay) {
// See if we can find GDK display using X11 display
gdk_display = gdk_x11_lookup_xdisplay(xdisplay);
}
if (!gdk_display) {
// If not then get the default display
gdk_display = gdk_display_get_default();
}
if (!gdk_display) {
// The tkinter_.py and hello_world.py examples do not use GTK
// internally, so GTK wasn't yet initialized and must do it
// now, so that display is available. Also must install X11
// error handlers to avoid 'BadWindow' errors.
// --
// A similar code is in cefpython_app.cpp and it might already
// been executed. If making changes here, make changes there
// as well.
LOG(INFO) << "[Browser process] Initialize GTK";
gtk_init(0, NULL);
InstallX11ErrorHandlers();
// Now the display is available
gdk_display = gdk_display_get_default();
}
// In kivy_.py example getting error message:
// > Can't create GtkPlug as child of non-GtkSocket
// However dialog handler works just fine.
GtkWidget* widget = gtk_plug_new_for_display(gdk_display, xwindow);
// Getting top level widget doesn't seem to be required.
// OFF: GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
GtkWindow* window = GTK_WINDOW(widget);
if (!window) {
LOG(ERROR) << "No GtkWindow for browser";
}
return window;
}
XImage* CefBrowser_GetImage(CefRefPtr<CefBrowser> browser) {
REQUIRE_UI_THREAD();
// See SetX11WindowBounds: NULL off the UI thread or on a non-X11 Ozone
// backend.
::Display* display = cef_get_xdisplay();
if (!display) {
LOG(ERROR) << "cef_get_xdisplay() returned NULL in CefBrowser_GetImage"
" (wrong thread or non-X11 backend)";
return NULL;
}
::Window browser_window = browser->GetHost()->GetWindowHandle();
XWindowAttributes attrs;
if (!XGetWindowAttributes(display, browser_window, &attrs)) {
LOG(ERROR) << "XGetWindowAttributes failed in CefBrowser_GetImage";
return NULL;
}
XImage* image = XGetImage(display, browser_window,
0, 0, attrs.width, attrs.height,
AllPlanes, ZPixmap);
if (!image) {
LOG(ERROR) << "XGetImage failed in CefBrowser_GetImage";
return NULL;
}
return image;
}