forked from cztomczak/cefpython
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathx11.cpp
More file actions
144 lines (134 loc) · 5.54 KB
/
Copy pathx11.cpp
File metadata and controls
144 lines (134 loc) · 5.54 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
// 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 "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) {
::Window xwindow = browser->GetHost()->GetWindowHandle();
::Display* xdisplay = cef_get_xdisplay();
if (!xdisplay || !xwindow) 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) {
::Window xwindow = browser->GetHost()->GetWindowHandle();
::Display* xdisplay = cef_get_xdisplay();
if (!xdisplay || !xwindow) return;
XStoreName(xdisplay, xwindow, title);
}
void HideX11ShellWindow(CefRefPtr<CefBrowser> browser) {
// On native Wayland (ozone-platform=wayland) with SUPPORTS_OZONE_X11
// compiled in, CEF's CreateHostWindow() creates two separate windows:
// 1. An X11/XWayland top-level shell (CefWindowX11) — empty, visible
// 2. A Wayland xdg_toplevel (NativeWidgetDelegate) — holds the content
// Unmap the empty X11 shell so only the content-bearing Wayland window
// is visible to the user.
::Window xwindow = browser->GetHost()->GetWindowHandle();
::Display* xdisplay = cef_get_xdisplay();
if (!xdisplay || !xwindow) return;
XUnmapWindow(xdisplay, xwindow);
XFlush(xdisplay);
}
GtkWindow* CefBrowser_GetGtkWindow(CefRefPtr<CefBrowser> browser) {
// TODO: Should return NULL when using the Views framework
// -- REWRITTEN FOR CEF PYTHON USE CASE --
//
// WARNING (CEF 146 Ozone X11): gtk_plug_new_for_display() below sends an
// XEMBED_EMBEDDED_NOTIFY to the browser's X11 window, which causes GTK to
// call XReparentWindow and move the browser window into a new GtkSocket.
// This breaks embedded-window positioning. Only call this function when
// showing a transient dialog (file chooser, print dialog) where the browser
// window displacement is acceptable or the dialog is temporary.
//
// 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) {
::Display* display = cef_get_xdisplay();
if (!display) {
LOG(ERROR) << "cef_get_xdisplay() returned NULL in CefBrowser_GetImage";
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;
}