Flutter Engine
fl_renderer_x11.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "fl_renderer_x11.h"
6 #ifdef GDK_WINDOWING_X11
7 
8 #include <X11/X.h>
9 
10 #include "flutter/shell/platform/linux/egl_utils.h"
11 
12 struct _FlRendererX11 {
13  FlRenderer parent_instance;
14 
15  // Connection to the X server.
16  Display* display;
17 };
18 
19 G_DEFINE_TYPE(FlRendererX11, fl_renderer_x11, fl_renderer_get_type())
20 
21 static void fl_renderer_x11_dispose(GObject* object) {
22  FlRendererX11* self = FL_RENDERER_X11(object);
23 
24  if (self->display != nullptr) {
25  XCloseDisplay(self->display);
26  self->display = nullptr;
27  }
28 
29  G_OBJECT_CLASS(fl_renderer_x11_parent_class)->dispose(object);
30 }
31 
32 // Implements FlRenderer::setup_window_attr.
33 static gboolean fl_renderer_x11_setup_window_attr(
34  FlRenderer* renderer,
35  GtkWidget* widget,
36  EGLDisplay display,
37  EGLConfig config,
38  GdkWindowAttr* window_attributes,
39  gint* mask,
40  GError** error) {
41  EGLint visual_id;
42  if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visual_id)) {
44  "Failed to determine EGL configuration visual");
45  return FALSE;
46  }
47 
48  GdkX11Screen* screen = GDK_X11_SCREEN(gtk_widget_get_screen(widget));
49  if (!screen) {
51  "View widget is not on an X11 screen");
52  return FALSE;
53  }
54 
55  window_attributes->visual = gdk_x11_screen_lookup_visual(screen, visual_id);
56  if (window_attributes->visual == nullptr) {
58  "Failed to find visual 0x%x", visual_id);
59  return FALSE;
60  }
61 
62  *mask |= GDK_WA_VISUAL;
63 
64  return TRUE;
65 }
66 
67 // Implements FlRenderer::create_display.
68 static EGLDisplay fl_renderer_x11_create_display(FlRenderer* renderer) {
69  FlRendererX11* self = FL_RENDERER_X11(renderer);
70 
71  // Create a dedicated connection to the X server because the EGL calls are
72  // made from Flutter on a different thread to GTK. Re-using the existing
73  // GTK X11 connection would crash as Xlib is not thread safe.
74  if (self->display == nullptr) {
75  Display* display = gdk_x11_get_default_xdisplay();
76  self->display = XOpenDisplay(DisplayString(display));
77  }
78 
79  return eglGetDisplay(self->display);
80 }
81 
82 // Implements FlRenderer::create_surfaces.
83 static gboolean fl_renderer_x11_create_surfaces(FlRenderer* renderer,
84  GtkWidget* widget,
85  EGLDisplay display,
86  EGLConfig config,
87  EGLSurface* visible,
88  EGLSurface* resource,
89  GError** error) {
90  GdkWindow* window = gtk_widget_get_window(widget);
91  if (!GDK_IS_X11_WINDOW(window)) {
92  g_set_error(
94  "Can not create EGL surface: view doesn't have an X11 GDK window");
95  return FALSE;
96  }
97 
98  *visible = eglCreateWindowSurface(display, config,
99  gdk_x11_window_get_xid(window), nullptr);
100  if (*visible == EGL_NO_SURFACE) {
101  EGLint egl_error = eglGetError(); // Must be before egl_config_to_string().
102  g_autofree gchar* config_string = egl_config_to_string(display, config);
104  "Failed to create EGL surface using configuration (%s): %s",
105  config_string, egl_error_to_string(egl_error));
106  return FALSE;
107  }
108 
109  const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
110  *resource = eglCreatePbufferSurface(display, config, attribs);
111  if (*resource == EGL_NO_SURFACE) {
112  EGLint egl_error = eglGetError(); // Must be before egl_config_to_string().
113  g_autofree gchar* config_string = egl_config_to_string(display, config);
115  "Failed to create EGL resource using configuration (%s): %s",
116  config_string, egl_error_to_string(egl_error));
117  return FALSE;
118  }
119 
120  return TRUE;
121 }
122 
123 static void fl_renderer_x11_class_init(FlRendererX11Class* klass) {
124  G_OBJECT_CLASS(klass)->dispose = fl_renderer_x11_dispose;
125  FL_RENDERER_CLASS(klass)->setup_window_attr =
126  fl_renderer_x11_setup_window_attr;
127  FL_RENDERER_CLASS(klass)->create_display = fl_renderer_x11_create_display;
128  FL_RENDERER_CLASS(klass)->create_surfaces = fl_renderer_x11_create_surfaces;
129 }
130 
131 static void fl_renderer_x11_init(FlRendererX11* self) {}
132 
133 FlRendererX11* fl_renderer_x11_new() {
134  return FL_RENDERER_X11(g_object_new(fl_renderer_x11_get_type(), nullptr));
135 }
136 
137 #endif // GDK_WINDOWING_X11
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
Definition: mock_egl.cc:153
FlMethodResponse GError ** error
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
Definition: mock_egl.cc:248
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
Definition: mock_egl.cc:142
GQuark fl_renderer_error_quark(void) G_GNUC_CONST
EGLint eglGetError()
Definition: mock_egl.cc:252
gchar * egl_config_to_string(EGLDisplay display, EGLConfig config)
Definition: egl_utils.cc:126
const gchar * egl_error_to_string(EGLint error)
Definition: egl_utils.cc:89
return TRUE
Definition: fl_view.cc:107
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
Definition: mock_egl.cc:132