forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fl_gl_area.cc
134 lines (104 loc) · 4.23 KB
/
fl_gl_area.cc
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
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/linux/fl_gl_area.h"
#include <epoxy/gl.h>
struct _FlGLArea {
GtkWidget parent_instance;
GdkGLContext* context;
FlBackingStoreProvider* texture;
};
G_DEFINE_TYPE(FlGLArea, fl_gl_area, GTK_TYPE_WIDGET)
static void fl_gl_area_dispose(GObject* gobject) {
FlGLArea* self = FL_GL_AREA(gobject);
g_clear_object(&self->context);
g_clear_object(&self->texture);
G_OBJECT_CLASS(fl_gl_area_parent_class)->dispose(gobject);
}
// Implements GtkWidget::realize.
static void fl_gl_area_realize(GtkWidget* widget) {
GtkAllocation allocation;
gtk_widget_get_allocation(widget, &allocation);
gtk_widget_set_realized(widget, TRUE);
GdkWindowAttr attributes;
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gtk_widget_get_visual(widget);
attributes.event_mask = gtk_widget_get_events(widget);
gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget),
&attributes, attributes_mask);
gtk_widget_set_window(widget, window);
gtk_widget_register_window(widget, window);
}
// Implements GtkWidget::unrealize.
static void fl_gl_area_unrealize(GtkWidget* widget) {
FlGLArea* self = FL_GL_AREA(widget);
gdk_gl_context_make_current(self->context);
g_clear_object(&self->texture);
/* Make sure to unset the context if current */
if (self->context == gdk_gl_context_get_current()) {
gdk_gl_context_clear_current();
}
GTK_WIDGET_CLASS(fl_gl_area_parent_class)->unrealize(widget);
}
// Implements GtkWidget::size_allocate.
static void fl_gl_area_size_allocate(GtkWidget* widget,
GtkAllocation* allocation) {
gtk_widget_set_allocation(widget, allocation);
if (gtk_widget_get_has_window(widget)) {
if (gtk_widget_get_realized(widget)) {
gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x,
allocation->y, allocation->width,
allocation->height);
}
}
}
// Implements GtkWidget::draw.
static gboolean fl_gl_area_draw(GtkWidget* widget, cairo_t* cr) {
FlGLArea* self = FL_GL_AREA(widget);
gdk_gl_context_make_current(self->context);
gint scale = gtk_widget_get_scale_factor(widget);
if (self->texture) {
uint32_t texture =
fl_backing_store_provider_get_gl_texture_id(self->texture);
GdkRectangle geometry =
fl_backing_store_provider_get_geometry(self->texture);
gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(widget), texture,
GL_TEXTURE, scale, geometry.x, geometry.y,
geometry.width, geometry.height);
gdk_gl_context_make_current(self->context);
}
return TRUE;
}
static void fl_gl_area_class_init(FlGLAreaClass* klass) {
GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
gobject_class->dispose = fl_gl_area_dispose;
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
widget_class->realize = fl_gl_area_realize;
widget_class->unrealize = fl_gl_area_unrealize;
widget_class->size_allocate = fl_gl_area_size_allocate;
widget_class->draw = fl_gl_area_draw;
gtk_widget_class_set_accessible_role(widget_class, ATK_ROLE_DRAWING_AREA);
}
static void fl_gl_area_init(FlGLArea* self) {
gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE);
gtk_widget_set_app_paintable(GTK_WIDGET(self), TRUE);
}
GtkWidget* fl_gl_area_new(GdkGLContext* context) {
g_return_val_if_fail(GDK_IS_GL_CONTEXT(context), nullptr);
FlGLArea* area =
reinterpret_cast<FlGLArea*>(g_object_new(fl_gl_area_get_type(), nullptr));
area->context = GDK_GL_CONTEXT(g_object_ref(context));
return GTK_WIDGET(area);
}
void fl_gl_area_queue_render(FlGLArea* self, FlBackingStoreProvider* texture) {
g_return_if_fail(FL_IS_GL_AREA(self));
g_clear_object(&self->texture);
g_set_object(&self->texture, texture);
gtk_widget_queue_draw(GTK_WIDGET(self));
}