320 lines
11 KiB
C++
320 lines
11 KiB
C++
|
// Copyright 2018 The Chromium OS 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 <math.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <wayland-client.h>
|
||
|
#include <wayland-client-protocol.h>
|
||
|
|
||
|
#include "base/command_line.h"
|
||
|
#include "base/logging.h"
|
||
|
#include "base/memory/shared_memory.h"
|
||
|
#include "base/strings/string_number_conversions.h"
|
||
|
#include "brillo/syslog_logging.h"
|
||
|
|
||
|
constexpr char kBgColorFlag[] = "bgcolor";
|
||
|
constexpr char kWidthFlag[] = "width";
|
||
|
constexpr char kHeightFlag[] = "height";
|
||
|
constexpr char kTitleFlag[] = "title";
|
||
|
|
||
|
struct demo_data {
|
||
|
uint32_t bgcolor;
|
||
|
uint32_t width;
|
||
|
uint32_t height;
|
||
|
std::string title;
|
||
|
int scale;
|
||
|
struct wl_compositor* compositor;
|
||
|
struct wl_shell* shell;
|
||
|
struct wl_shm* shm;
|
||
|
struct wl_surface* surface;
|
||
|
struct wl_shell_surface* shell_surface;
|
||
|
struct wl_buffer* buffer;
|
||
|
struct wl_callback* callback;
|
||
|
struct wl_callback_listener* callback_listener;
|
||
|
struct wl_output* output;
|
||
|
struct wl_output_listener* output_listener;
|
||
|
struct wl_keyboard_listener* keyboard_listener;
|
||
|
void* shm_ptr;
|
||
|
bool done;
|
||
|
};
|
||
|
|
||
|
void keyboard_keymap(void* data,
|
||
|
struct wl_keyboard* keyboard,
|
||
|
uint32_t format,
|
||
|
int32_t fd,
|
||
|
uint32_t size) {}
|
||
|
|
||
|
void keyboard_enter(void* data,
|
||
|
struct wl_keyboard* keyboard,
|
||
|
uint32_t serial,
|
||
|
struct wl_surface* surface,
|
||
|
struct wl_array* keys) {}
|
||
|
|
||
|
void keyboard_leave(void* data,
|
||
|
struct wl_keyboard* keyboard,
|
||
|
uint32_t serial,
|
||
|
struct wl_surface* surface) {}
|
||
|
|
||
|
void keyboard_key(void* data,
|
||
|
struct wl_keyboard* keyboard,
|
||
|
uint32_t serial,
|
||
|
uint32_t time,
|
||
|
uint32_t key,
|
||
|
uint32_t state) {
|
||
|
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||
|
// Key pressed.
|
||
|
if (state == 1) {
|
||
|
LOG(INFO) << "wayland_demo application detected keypress";
|
||
|
data_ptr->done = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void keyboard_modifiers(void* data,
|
||
|
struct wl_keyboard* keyboard,
|
||
|
uint32_t serial,
|
||
|
uint32_t mods_depressed,
|
||
|
uint32_t mods_latched,
|
||
|
uint32_t mods_locked,
|
||
|
uint32_t group) {}
|
||
|
|
||
|
void keyboard_repeat_info(void* data,
|
||
|
struct wl_keyboard* keyboard,
|
||
|
int32_t rate,
|
||
|
int32_t delay) {}
|
||
|
|
||
|
void demo_registry_listener(void* data,
|
||
|
struct wl_registry* registry,
|
||
|
uint32_t id,
|
||
|
const char* interface,
|
||
|
uint32_t version) {
|
||
|
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||
|
if (!strcmp("wl_compositor", interface)) {
|
||
|
data_ptr->compositor = reinterpret_cast<struct wl_compositor*>(
|
||
|
wl_registry_bind(registry, id, &wl_compositor_interface, version));
|
||
|
} else if (!strcmp("wl_shell", interface)) {
|
||
|
data_ptr->shell = reinterpret_cast<struct wl_shell*>(
|
||
|
wl_registry_bind(registry, id, &wl_shell_interface, version));
|
||
|
} else if (!strcmp("wl_shm", interface)) {
|
||
|
data_ptr->shm = reinterpret_cast<struct wl_shm*>(
|
||
|
wl_registry_bind(registry, id, &wl_shm_interface, version));
|
||
|
} else if (!strcmp("wl_output", interface)) {
|
||
|
data_ptr->output = reinterpret_cast<struct wl_output*>(
|
||
|
wl_registry_bind(registry, id, &wl_output_interface, version));
|
||
|
wl_output_add_listener(data_ptr->output, data_ptr->output_listener,
|
||
|
data_ptr);
|
||
|
} else if (!strcmp("wl_seat", interface)) {
|
||
|
struct wl_seat* seat = reinterpret_cast<struct wl_seat*>(
|
||
|
wl_registry_bind(registry, id, &wl_seat_interface, version));
|
||
|
wl_keyboard_add_listener(wl_seat_get_keyboard(seat),
|
||
|
data_ptr->keyboard_listener, data_ptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void demo_registry_remover(void* data,
|
||
|
struct wl_registry* registry,
|
||
|
uint32_t id) {}
|
||
|
|
||
|
void shell_surface_ping(void* data,
|
||
|
struct wl_shell_surface* shell_surface,
|
||
|
uint32_t serial) {
|
||
|
wl_shell_surface_pong(shell_surface, serial);
|
||
|
}
|
||
|
|
||
|
void shell_surface_configure(void* data,
|
||
|
struct wl_shell_surface* shell_surface,
|
||
|
uint32_t edges,
|
||
|
int32_t width,
|
||
|
int32_t height) {}
|
||
|
|
||
|
void shell_surface_popup_done(void* data,
|
||
|
struct wl_shell_surface* shell_surface) {}
|
||
|
|
||
|
void demo_draw(void* data, struct wl_callback* callback, uint32_t time) {
|
||
|
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||
|
wl_callback_destroy(data_ptr->callback);
|
||
|
wl_surface_damage(data_ptr->surface, 0, 0, data_ptr->width, data_ptr->height);
|
||
|
uint32_t* surface_data = reinterpret_cast<uint32_t*>(data_ptr->shm_ptr);
|
||
|
for (int i = 0; i < data_ptr->width * data_ptr->height; ++i) {
|
||
|
surface_data[i] = data_ptr->bgcolor;
|
||
|
}
|
||
|
data_ptr->callback = wl_surface_frame(data_ptr->surface);
|
||
|
wl_surface_attach(data_ptr->surface, data_ptr->buffer, 0, 0);
|
||
|
wl_callback_add_listener(data_ptr->callback, data_ptr->callback_listener,
|
||
|
data_ptr);
|
||
|
wl_surface_commit(data_ptr->surface);
|
||
|
}
|
||
|
|
||
|
void output_geometry(void* data,
|
||
|
struct wl_output* output,
|
||
|
int32_t x,
|
||
|
int32_t y,
|
||
|
int32_t physical_width,
|
||
|
int32_t physical_height,
|
||
|
int32_t subpixel,
|
||
|
const char* make,
|
||
|
const char* model,
|
||
|
int32_t transform) {}
|
||
|
|
||
|
void output_mode(void* data,
|
||
|
struct wl_output* output,
|
||
|
uint32_t flags,
|
||
|
int32_t width,
|
||
|
int32_t height,
|
||
|
int32_t refresh) {
|
||
|
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||
|
if (data_ptr->width == 0) {
|
||
|
data_ptr->width = width;
|
||
|
if (data_ptr->scale != 0) {
|
||
|
data_ptr->width /= data_ptr->scale;
|
||
|
}
|
||
|
}
|
||
|
if (data_ptr->height == 0) {
|
||
|
data_ptr->height = height;
|
||
|
if (data_ptr->scale != 0) {
|
||
|
data_ptr->height /= data_ptr->scale;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void output_done(void* data, struct wl_output* output) {}
|
||
|
|
||
|
void output_scale(void* data, struct wl_output* output, int32_t factor) {
|
||
|
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||
|
data_ptr->scale = factor;
|
||
|
if (data_ptr->width != 0) {
|
||
|
data_ptr->width /= factor;
|
||
|
}
|
||
|
if (data_ptr->height != 0) {
|
||
|
data_ptr->height /= factor;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int main(int argc, char* argv[]) {
|
||
|
brillo::InitLog(brillo::kLogToSyslog);
|
||
|
LOG(INFO) << "Starting wayland_demo application";
|
||
|
|
||
|
base::CommandLine::Init(argc, argv);
|
||
|
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
|
||
|
struct demo_data data;
|
||
|
memset(&data, 0, sizeof(data));
|
||
|
data.done = false;
|
||
|
|
||
|
data.bgcolor = 0x3388DD;
|
||
|
if (cl->HasSwitch(kBgColorFlag)) {
|
||
|
data.bgcolor =
|
||
|
strtoul(cl->GetSwitchValueASCII(kBgColorFlag).c_str(), nullptr, 0);
|
||
|
}
|
||
|
if (cl->HasSwitch(kWidthFlag)) {
|
||
|
if (!base::StringToUint(cl->GetSwitchValueASCII(kWidthFlag), &data.width)) {
|
||
|
LOG(ERROR) << "Invalid width parameter passed";
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
if (cl->HasSwitch(kHeightFlag)) {
|
||
|
if (!base::StringToUint(cl->GetSwitchValueASCII(kHeightFlag),
|
||
|
&data.height)) {
|
||
|
LOG(ERROR) << "Invalid height parameter passed";
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
data.title = "wayland_demo";
|
||
|
if (cl->HasSwitch(kTitleFlag)) {
|
||
|
data.title = cl->GetSwitchValueASCII(kTitleFlag);
|
||
|
}
|
||
|
|
||
|
struct wl_display* display = wl_display_connect(nullptr);
|
||
|
if (!display) {
|
||
|
LOG(ERROR) << "Failed connecting to display";
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
struct wl_output_listener output_listener = {output_geometry, output_mode,
|
||
|
output_done, output_scale};
|
||
|
data.output_listener = &output_listener;
|
||
|
struct wl_registry_listener registry_listener = {
|
||
|
demo_registry_listener, demo_registry_remover,
|
||
|
};
|
||
|
struct wl_keyboard_listener keyboard_listener = {
|
||
|
keyboard_keymap, keyboard_enter, keyboard_leave,
|
||
|
keyboard_key, keyboard_modifiers, keyboard_repeat_info};
|
||
|
data.keyboard_listener = &keyboard_listener;
|
||
|
|
||
|
struct wl_registry* registry = wl_display_get_registry(display);
|
||
|
wl_registry_add_listener(registry, ®istry_listener, &data);
|
||
|
|
||
|
wl_display_dispatch(display);
|
||
|
wl_display_roundtrip(display);
|
||
|
|
||
|
if (!data.compositor) {
|
||
|
LOG(ERROR) << "Failed to find compositor";
|
||
|
return -1;
|
||
|
}
|
||
|
if (!data.output) {
|
||
|
LOG(ERROR) << "Failed to get output";
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// Do another roundtrip to ensure we get the wl_output callbacks.
|
||
|
wl_display_roundtrip(display);
|
||
|
|
||
|
data.surface = wl_compositor_create_surface(data.compositor);
|
||
|
if (!data.surface) {
|
||
|
LOG(ERROR) << "Failed creating surface";
|
||
|
return -1;
|
||
|
}
|
||
|
if (!data.shell) {
|
||
|
LOG(ERROR) << "Failed getting shell";
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
data.shell_surface = wl_shell_get_shell_surface(data.shell, data.surface);
|
||
|
if (!data.shell_surface) {
|
||
|
LOG(ERROR) << "Failed getting shell surface";
|
||
|
return -1;
|
||
|
}
|
||
|
const struct wl_shell_surface_listener shell_surface_listener = {
|
||
|
shell_surface_ping, shell_surface_configure, shell_surface_popup_done};
|
||
|
wl_shell_surface_add_listener(data.shell_surface, &shell_surface_listener,
|
||
|
nullptr);
|
||
|
|
||
|
wl_shell_surface_set_toplevel(data.shell_surface);
|
||
|
wl_shell_surface_set_class(data.shell_surface, data.title.c_str());
|
||
|
wl_shell_surface_set_title(data.shell_surface, data.title.c_str());
|
||
|
data.callback = wl_surface_frame(data.surface);
|
||
|
struct wl_callback_listener callback_listener = {demo_draw};
|
||
|
data.callback_listener = &callback_listener;
|
||
|
wl_callback_add_listener(data.callback, data.callback_listener, &data);
|
||
|
|
||
|
if (!data.shm) {
|
||
|
LOG(ERROR) << "Failed getting shared memory";
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
size_t stride = data.width * 4 /* 32bpp */;
|
||
|
size_t shm_size = stride * data.height;
|
||
|
base::SharedMemory shared_mem;
|
||
|
shared_mem.CreateAndMapAnonymous(shm_size);
|
||
|
data.shm_ptr = shared_mem.memory();
|
||
|
|
||
|
struct wl_shm_pool* pool =
|
||
|
wl_shm_create_pool(data.shm, shared_mem.handle().fd, shm_size);
|
||
|
data.buffer = wl_shm_pool_create_buffer(pool, 0, data.width, data.height,
|
||
|
stride, WL_SHM_FORMAT_XRGB8888);
|
||
|
wl_shm_pool_destroy(pool);
|
||
|
|
||
|
wl_surface_attach(data.surface, data.buffer, 0, 0);
|
||
|
wl_surface_commit(data.surface);
|
||
|
|
||
|
demo_draw(&data, nullptr, 0);
|
||
|
LOG(INFO) << "wayland_demo application displaying, waiting for keypress";
|
||
|
do {
|
||
|
} while (wl_display_dispatch(display) != -1 && !data.done);
|
||
|
|
||
|
wl_display_disconnect(display);
|
||
|
LOG(INFO) << "wayland_demo application exiting";
|
||
|
return 0;
|
||
|
}
|