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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
//
// Implementation of the Wayland graphics driver.
//
// Copyright 2021-2022 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
// https://www.fltk.org/bugs.php
//
#include <config.h>
#include <FL/platform.H>
#include "Fl_Wayland_Graphics_Driver.H"
#include "Fl_Wayland_Screen_Driver.H"
#include "Fl_Wayland_Window_Driver.H"
#include "text-input-client-protocol.h"
#include <pango/pangocairo.h>
#if ! PANGO_VERSION_CHECK(1,22,0)
# error "Requires Pango 1.22 or higher"
#endif
#define _GNU_SOURCE 1
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
extern unsigned fl_cmap[256]; // defined in fl_color.cxx
extern "C" {
int os_create_anonymous_file(off_t);
}
struct fl_wld_buffer *Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, int height)
{
struct fl_wld_buffer *buffer;
int stride = cairo_format_stride_for_width(Fl_Cairo_Graphics_Driver::cairo_format, width);
int size = stride * height;
static char *pool_memory = NULL;
static int pool_size = 10000000; // gets increased if necessary
static int chunk_offset = pool_size;
static int fd = -1;
static struct wl_shm_pool *pool = NULL;
if (chunk_offset + size > pool_size) {
chunk_offset = 0;
if (pool) {
wl_shm_pool_destroy(pool);
close(fd);
}
if (size > pool_size) pool_size = 2 * size;
fd = os_create_anonymous_file(pool_size);
pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pool_memory == MAP_FAILED) {
close(fd);
Fl::fatal("mmap failed: %s\n", strerror(errno));
}
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
pool = wl_shm_create_pool(scr_driver->wl_shm, fd, pool_size);
}
buffer = (struct fl_wld_buffer*)calloc(1, sizeof(struct fl_wld_buffer));
buffer->stride = stride;
buffer->wl_buffer = wl_shm_pool_create_buffer(pool, chunk_offset, width, height, stride, Fl_Wayland_Graphics_Driver::wld_format);
buffer->data = (void*)(pool_memory + chunk_offset);
chunk_offset += size;
buffer->data_size = size;
buffer->width = width;
buffer->draw_buffer = new uchar[buffer->data_size];
buffer->draw_buffer_needs_commit = false;
//fprintf(stderr, "create_shm_buffer: %dx%d = %d\n", width, height, size);
cairo_init(buffer, width, height, stride, Fl_Cairo_Graphics_Driver::cairo_format);
return buffer;
}
void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window) {
cairo_surface_t *surf = cairo_get_target(window->buffer->cairo_);
cairo_surface_flush(surf);
memcpy(window->buffer->data, window->buffer->draw_buffer, window->buffer->data_size);
wl_surface_attach(window->wl_surface, window->buffer->wl_buffer, 0, 0);
wl_surface_set_buffer_scale(window->wl_surface, window->scale);
wl_surface_commit(window->wl_surface);
window->buffer->draw_buffer_needs_commit = false;
//fprintf(stderr,"buffer_commit %s\n", window->fl_win->parent()?"child":"top");
}
void Fl_Wayland_Graphics_Driver::cairo_init(struct fl_wld_buffer *buffer, int width, int height, int stride, cairo_format_t format) {
cairo_surface_t *surf = cairo_image_surface_create_for_data(buffer->draw_buffer, format,
width, height, stride);
if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
Fl::fatal("Can't create Cairo surface with cairo_image_surface_create_for_data()\n");
return;
}
buffer->cairo_ = cairo_create(surf);
cairo_status_t err;
if ((err = cairo_status(buffer->cairo_)) != CAIRO_STATUS_SUCCESS) {
Fl::fatal("Cairo error during cairo_create() %s\n", cairo_status_to_string(err));
return;
}
cairo_surface_destroy(surf);
cairo_set_source_rgba(buffer->cairo_, 1.0, 1.0, 1.0, 0.);
cairo_paint(buffer->cairo_);
cairo_set_source_rgba(buffer->cairo_, .0, .0, .0, 1.0); // Black default color
cairo_save(buffer->cairo_);
}
void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window)
{
if (window->buffer) {
wl_buffer_destroy(window->buffer->wl_buffer);
delete[] window->buffer->draw_buffer;
window->buffer->draw_buffer = NULL;
cairo_destroy(window->buffer->cairo_);
free(window->buffer);
window->buffer = NULL;
}
}
// these 2 refer to the same memory layout for pixel data
const uint32_t Fl_Wayland_Graphics_Driver::wld_format = WL_SHM_FORMAT_ARGB8888;
Fl_Wayland_Graphics_Driver::Fl_Wayland_Graphics_Driver () : Fl_Cairo_Graphics_Driver() {
buffer_ = NULL;
}
void Fl_Wayland_Graphics_Driver::set_buffer(struct fl_wld_buffer *buffer, float scale) {
this->buffer_ = buffer;
set_cairo(buffer->cairo_, scale);
}
void Fl_Wayland_Graphics_Driver::set_color(Fl_Color i, unsigned c) {
if (fl_cmap[i] != c) {
fl_cmap[i] = c;
}
}
void Fl_Wayland_Graphics_Driver::set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) {
Fl_Wayland_Screen_Driver::insertion_point_location(x, y, height);
}
void Fl_Wayland_Graphics_Driver::reset_spot() {
Fl::compose_state = 0;
Fl_Wayland_Screen_Driver::next_marked_length = 0;
Fl_Wayland_Screen_Driver::insertion_point_location_is_valid = false;
}
void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy) {
// draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of the graphics driver's surface
int height = osrc->data_size / osrc->stride;
cairo_matrix_t matrix;
cairo_get_matrix(cairo_, &matrix);
double s = matrix.xx;
cairo_save(cairo_);
cairo_rectangle(cairo_, x, y, w, h);
cairo_clip(cairo_);
cairo_surface_t *surf = cairo_image_surface_create_for_data(osrc->draw_buffer, Fl_Cairo_Graphics_Driver::cairo_format, osrc->width, height, osrc->stride);
cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf);
cairo_set_source(cairo_, pat);
cairo_matrix_init_scale(&matrix, s, s);
cairo_matrix_translate(&matrix, -(x - srcx), -(y - srcy));
cairo_pattern_set_matrix(pat, &matrix);
cairo_mask(cairo_, pat);
cairo_pattern_destroy(pat);
cairo_surface_destroy(surf);
cairo_restore(cairo_);
}
void Fl_Wayland_Graphics_Driver::gc(void *off) {} // equivalent is done by activate()
void *Fl_Wayland_Graphics_Driver::gc() {
return buffer_;
}
|