这是楼主的第一个Wayland程序:
效果图:
程序源代码:
//wayland-hello.h
/*
Copyright (c) 第三界主 2014
代码使用MIT协议发布
*/
#ifndef WAYLAND_HELLO_H
#define WAYLAND_HELLO_H
#include
#include
#include
#include
#include
#include
#include
#include
/* 某些struct wl_开头的对象实际上是wl_proxy对象的id,与windows下的Handle类似。 */
typedef struct wl_display* HDISPLAY;
typedef struct wl_registry* HREGISTRY;
typedef struct wl_compositor* HCOMPOSITOR;
typedef struct wl_shell* HSHELL;
typedef struct wl_shm* HSHM;
typedef struct wl_shm_pool* HSHMPOOL;
typedef struct wl_seat* HSEAT;
typedef struct wl_pointer* HPOINTER;
typedef struct wl_surface* HSURFACE;
typedef struct wl_shell_surface * HSHELLSURFACE;
typedef struct wl_callback* HCALLBACK;
typedef struct wl_buffer* HBUFFER;
typedef struct wl_keyboard* HKEYBOARD;
typedef void* LPVOID;
typedef struct _WAYLANDREGISTRY
{
/* 所有API都需要wl_display */
HDISPLAY s_display;
/* 合成器 */
HCOMPOSITOR s_compositor;
/* shell提供接口,与窗口操作有关 */
HSHELL s_shell;
/* 缓存管理器,与绘制相关 */
HSHM s_shm;
uint32_t shm_formats;
/* 输入设备管理器,管理键盘鼠标 */
HSEAT s_seat;
/* 鼠标控制器 */
HPOINTER s_pointer;
/* 键盘控制器 */
HKEYBOARD s_keyboard;
/* 鼠标当前窗口 */
HSURFACE s_pointer_surface;
/* 键盘当前窗口 */
HSURFACE s_kb_surface;
} WAYLANDREGISTRY, *LPWAYLANDREGISTRY;
/* wayland的全局对象都放在registry中 */
LPWAYLANDREGISTRY wlGetRegistry();
typedef struct _PAINTBUFFER
{
HBUFFER buffer;
void *data;
int busy;
}PAINTBUFFER, *LPPAINTBUFFER;
typedef struct _PAINTSTRUCTURE
{
LPPAINTBUFFER buffer;
} PAINTSTRUCTURE, *LPPAINTSTRUCTURE;
typedef void(*REPAINTPROC)(HSURFACE hSurface, LPPAINTSTRUCTURE lpPaint, uint32_t time);
typedef struct _SURFACEPRIVATE
{
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
int width, height;
REPAINTPROC surfaceproc;
PAINTBUFFER buffer[2];
} SURFACEPRIVATE, *LPSURFACEPRIVATE;
typedef struct _SIZE
{
int width, height;
} SIZE;
typedef int POINTERPROC;
typedef int KEYBOARDPROC;
static inline HDISPLAY wlGetDisplay()
{
return wlGetRegistry()->s_display;
}
static inline HCOMPOSITOR wlGetCompositor()
{
return wlGetRegistry()->s_compositor;
}
static inline HSHELL wlGetShell()
{
return wlGetRegistry()->s_shell;
}
static inline HPOINTER wlGetPointer()
{
return wlGetRegistry()->s_pointer;
}
static inline HKEYBOARD wlGetKeyboard()
{
return wlGetRegistry()->s_keyboard;
}
LPSURFACEPRIVATE _wlGetSurfacePrivate(HSURFACE surface);
void _wlCreatePaintStructure(int width, int height, LPPAINTBUFFER lpBuffer);
void _wlSetFrameListener(HSURFACE surface);
void _wlDrawFrame(HSURFACE surface, uint32_t time);
void wlBeginPaint(HSURFACE surface, LPPAINTSTRUCTURE lpPaint);
void wlEndPaint(HSURFACE surface, LPPAINTSTRUCTURE lpPaint);
int wlInit();
void wlTerminate();
HSURFACE wlCreateSurface(const char* title, int width, int height);
void wlSetPaintProc(HSURFACE surface, REPAINTPROC surfaceproc);
void wlCallPaintProc(HSURFACE hSurface, LPPAINTSTRUCTURE lpPaint, uint32_t time);
void wlSetPointerProc(HSURFACE surface, POINTERPROC surfaceproc);
void wlSetKeyboardProc(HSURFACE surface, KEYBOARDPROC surfaceproc);
SIZE wlGetSurfaceSize(HSURFACE surface);
int wlDispatch();
#endif
//wayland-hello.c
/*
Copyright (c) 第三界主 2014
代码使用MIT协议发布
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "wayland-hello.h"
void pointer_enter(void *data, HPOINTER wl_pointer, uint32_t serial, HSURFACE surface,
wl_fixed_t surface_x, wl_fixed_t surface_y)
{
wlGetRegistry()->s_pointer_surface = surface;
}
void pointer_leave(void *data, HPOINTER wl_pointer, uint32_t serial, HSURFACE surface)
{
wlGetRegistry()->s_pointer_surface = NULL;
}
void pointer_motion(void *data, HPOINTER wl_pointer, uint32_t time,
wl_fixed_t surface_x, wl_fixed_t surface_y)
{
}
void pointer_button(void *data, HPOINTER wl_pointer, uint32_t serial,
uint32_t time, uint32_t button, uint32_t state)
{
HSURFACE hSurface = wlGetRegistry()->s_pointer_surface;
if (hSurface == NULL)
return;
if (BTN_LEFT == button && state == WL_POINTER_BUTTON_STATE_PRESSED)
{
HSHELLSURFACE hShellSurface = _wlGetSurfacePrivate(hSurface)->shell_surface;
wl_shell_surface_move(hShellSurface, wlGetRegistry()->s_seat, serial);
return;
}
}
void pointer_axis(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value)
{
}
struct wl_pointer_listener pointer_listener = {
.enter = pointer_enter,
.leave = pointer_leave,
.motion = pointer_motion,
.button = pointer_button,
.axis = pointer_axis
};
void keyboard_keymap(LPVOID data, HKEYBOARD wl_keyboard, uint32_t format,
int32_t fd, uint32_t size)
{
}
void keyboard_enter(LPVOID data, HKEYBOARD wl_keyboard, uint32_t serial,
HSURFACE surface, struct wl_array *keys)
{
printf("keyboard focus.\n");
}
void keyboard_leave(void *data, HKEYBOARD wl_keyboard, uint32_t serial, HSURFACE surface)
{
}
void keyboard_key(void *data, HKEYBOARD wl_keyboard,
uint32_t serial,
uint32_t time,
uint32_t key,
uint32_t state)
{
if (KEY_F4 == key && WL_KEYBOARD_KEY_STATE_PRESSED == state)
{
exit(0);
}
}
void keyboard_modifiers(void *data,
HKEYBOARD wl_keyboard,
uint32_t serial,
uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked,
uint32_t group)
{
}
struct wl_keyboard_listener keyboard_listener = {
.keymap = keyboard_keymap,
.enter = keyboard_enter,
.leave = keyboard_leave,
.key = keyboard_key,
.modifiers = keyboard_modifiers
};
static void handle_ping(LPVOID data, HSHELLSURFACE shell_surface, uint32_t serial)
{
wl_shell_surface_pong(shell_surface, serial);
}
static void handle_configure(LPVOID data, HSHELLSURFACE shell_surface,
uint32_t edges, int32_t width, int32_t height)
{
}
static void handle_popup_done(LPVOID data, HSHELLSURFACE shell_surface){
}
static const struct wl_shell_surface_listener shell_surface_listener = {
.ping = handle_ping,
.configure = handle_configure,
.popup_done = handle_popup_done
};
static void shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) {
wlGetRegistry()->shm_formats |= (1 << format);
}
struct wl_shm_listener shm_listenter = {
shm_format
};
void registry_global(LPVOID data, HREGISTRY registry, uint32_t id, const char *interface, uint32_t version)
{
if (strcmp(interface, "wl_compositor") == 0)
{
wlGetRegistry()->s_compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
}
else if (strcmp(interface, "wl_shell") == 0)
{
wlGetRegistry()->s_shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
}
else if (strcmp(interface, "wl_shm") == 0)
{
wlGetRegistry()->s_shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
wl_shm_add_listener(wlGetRegistry()->s_shm, &shm_listenter, NULL);
}
else if (strcmp(interface, "wl_seat") == 0)
{
wlGetRegistry()->s_seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
wlGetRegistry()->s_pointer = wl_seat_get_pointer(wlGetRegistry()->s_seat);
wlGetRegistry()->s_keyboard = wl_seat_get_keyboard(wlGetRegistry()->s_seat);
}
}
static void registry_global_remove(LPVOID data, HREGISTRY registry, uint32_t name)
{
}
static struct wl_registry_listener registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove
};
int wlInit()
{
wlGetRegistry()->s_display = wl_display_connect(NULL);
HREGISTRY registry = wl_display_get_registry(wlGetRegistry()->s_display);
/* wayland的API是异步的,需要给registry设置回掉函数 */
wl_registry_add_listener(registry, ®istry_listener, NULL);
/* 处理消息 */
wl_display_roundtrip(wlGetRegistry()->s_display);
wl_display_get_fd(wlGetRegistry()->s_display);
/* 处理鼠标消息 */
wl_pointer_add_listener(wlGetPointer(), &pointer_listener, NULL);
wl_keyboard_add_listener(wlGetKeyboard(), &keyboard_listener, NULL);
}
HSURFACE wlCreateSurface(const char* title, int width, int height)
{
/* wayland中,窗口被称作surface */
HSURFACE surface = wl_compositor_create_surface(wlGetCompositor());
/* shell_surface具有移动、改变大小、设置标题、最大化、最小化等功能 */
HSHELLSURFACE shell_surface = wl_shell_get_shell_surface(wlGetShell(), surface);
/* 窗口的私有数据 */
LPSURFACEPRIVATE surface_priv = (LPSURFACEPRIVATE)malloc(sizeof(SURFACEPRIVATE));
memset(surface_priv, 0, sizeof(SURFACEPRIVATE));
surface_priv->surface = surface;
surface_priv->shell_surface = shell_surface;
surface_priv->width = width;
surface_priv->height = height;
wl_surface_set_user_data(surface, surface_priv);
/* 设置响应函数 */
wl_shell_surface_add_listener(shell_surface, &shell_surface_listener, NULL);
wl_shell_surface_set_title(shell_surface, title);
wl_shell_surface_set_toplevel(shell_surface);
wl_surface_damage(surface, 0, 0, width, height);
return surface;
}
LPSURFACEPRIVATE _wlGetSurfacePrivate( HSURFACE surface )
{
return (LPSURFACEPRIVATE)wl_surface_get_user_data(surface);
}
void frame_listener_done(void *data, HCALLBACK callback, uint32_t time)
{
HSURFACE surface = (HSURFACE)data;
/* 每次都需要重新设置回调函数 */
_wlSetFrameListener(surface);
/* 绘制一帧 */
_wlDrawFrame(surface, time);
}
static struct wl_callback_listener frame_listener = {
.done = frame_listener_done
};
void _wlSetFrameListener(HSURFACE surface)
{
HCALLBACK callback = wl_surface_frame(surface);
wl_callback_add_listener(callback, &frame_listener, surface);
}
void _wlDrawFrame(HSURFACE surface, uint32_t time)
{
PAINTSTRUCTURE ps;
memset(&ps, 0, sizeof(ps));
wlBeginPaint(surface, &ps);
wlCallPaintProc(surface, &ps, time);
wlEndPaint(surface, &ps);
}
void wlSetPaintProc(HSURFACE surface, REPAINTPROC surfaceproc)
{
_wlGetSurfacePrivate(surface)->surfaceproc = surfaceproc;
_wlSetFrameListener(surface);
_wlDrawFrame(surface, 0);
}
void wlTerminate()
{
wl_display_disconnect(wlGetDisplay());
}
void buffer_release(void *data, struct wl_buffer *buffer)
{
LPPAINTBUFFER lpBuffer = data;
lpBuffer->busy = 0;
}
static const struct wl_buffer_listener buffer_listener = {
.release = buffer_release
};
void _wlCreatePaintStructure(int width, int height, LPPAINTBUFFER lpBuffer)
{
int stride = width * 4;
int size = stride * height;
char filename[] = "/tmp/weston-shared-XXXXXX";
int fd = mkstemp(filename);
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
unlink(filename);
ftruncate(fd, size);
lpBuffer->busy = 0;
lpBuffer->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
//lpBuffer->data == MAP_FAILED
HSHMPOOL pool = wl_shm_create_pool(wlGetRegistry()->s_shm, fd, size);
lpBuffer->buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
wl_buffer_add_listener(lpBuffer->buffer, &buffer_listener, lpBuffer);
wl_shm_pool_destroy(pool);
close(fd);
}
void wlBeginPaint(HSURFACE surface, LPPAINTSTRUCTURE lpPaint)
{
LPSURFACEPRIVATE _priv = _wlGetSurfacePrivate(surface);
if (!_priv->buffer[0].busy && _priv->buffer[0].buffer)
{
lpPaint->buffer = &_priv->buffer[0];
}
else if (!_priv->buffer[1].busy && _priv->buffer[1].buffer)
{
lpPaint->buffer = &_priv->buffer[1];
}
else
{
SIZE sz = wlGetSurfaceSize(surface);
_wlCreatePaintStructure(sz.width, sz.height, &_priv->buffer[0]);
lpPaint->buffer = &_priv->buffer[0];
}
}
void wlEndPaint(HSURFACE surface, LPPAINTSTRUCTURE lpPaint)
{
lpPaint->buffer->busy = 1;
wl_surface_attach(surface, lpPaint->buffer->buffer, 0, 0);
SIZE sz = wlGetSurfaceSize(surface);
wl_surface_damage(surface, 0, 0, sz.width, sz.height);
wl_surface_commit(surface);
}
SIZE wlGetSurfaceSize(HSURFACE surface)
{
SIZE sz;
sz.width = _wlGetSurfacePrivate(surface)->width;
sz.height = _wlGetSurfacePrivate(surface)->height;
return sz;
}
int wlDispatch()
{
return wl_display_dispatch(wlGetDisplay());
}
void wlCallPaintProc(HSURFACE hSurface, LPPAINTSTRUCTURE lpPaint, uint32_t time)
{
LPSURFACEPRIVATE _private = _wlGetSurfacePrivate(hSurface);
if (_private->surfaceproc)
{
_private->surfaceproc(hSurface, lpPaint, time);
}
}
LPWAYLANDREGISTRY wlGetRegistry()
{
static WAYLANDREGISTRY registry;
static int bInit = 1;
if (bInit)
{
memset(®istry, 0, sizeof(registry));
bInit = 0;
}
return ®istry;
}
//main.c
void PaintProc(HSURFACE hSurface)
{
PAINTSTRUCTURE ps;
memset(&ps, 0, sizeof(ps));
wlBeginPaint(hSurface, &ps);
memset(ps.lpBuffer->lpPixelBuffer, 0xff, ps.lpBuffer->length);
SIZE sz = wlGetSurfaceSize(hSurface);
//paint_pixels(ps.lpBuffer->lpPixelBuffer, 20, sz.width, sz.height, ps.uTime);
HCAIROSURFACE hCairoSurface = ps.lpBuffer->hCairoSurface; // 类似与 HWND
HCAIRO hdc = cairo_create(hCairoSurface); // 类似于 HDC
cairo_set_source_rgb(hdc,0, 0.4, 0.8);
cairo_set_line_width(hdc, 50);
cairo_move_to(hdc, 0, 0);
cairo_line_to(hdc, sz.width, 0);
cairo_stroke(hdc);
cairo_set_source_rgb(hdc, 0 , 0, 0);
cairo_move_to(hdc, 10, 20);
cairo_set_font_size(hdc, 18);
cairo_show_text(hdc, "这是标题栏");
cairo_stroke(hdc);
int btnCloseHeight = 20;
int btnCloseWidth = 20;
int btnCloseLineWidth = 2;
cairo_set_source_rgb(hdc, 1, 0, 0);
cairo_set_line_width(hdc, 2);
cairo_move_to(hdc, sz.width-btnCloseWidth, btnCloseLineWidth/2); cairo_line_to(hdc, sz.width, btnCloseLineWidth/2);
cairo_move_to(hdc, sz.width-btnCloseWidth, 0); cairo_line_to(hdc, sz.width-btnCloseWidth, btnCloseHeight);
cairo_move_to(hdc, sz.width, 0); cairo_line_to(hdc, sz.width, btnCloseHeight);
cairo_move_to(hdc, sz.width-btnCloseWidth, btnCloseHeight); cairo_line_to(hdc, sz.width, btnCloseHeight);
cairo_move_to(hdc, sz.width-btnCloseWidth, btnCloseLineWidth/2); cairo_line_to(hdc, sz.width, btnCloseHeight);
cairo_move_to(hdc, sz.width, btnCloseLineWidth/2); cairo_line_to(hdc, sz.width-btnCloseWidth, btnCloseHeight);
cairo_stroke(hdc);
cairo_set_source_rgb(hdc, 0 , 0, 0);
cairo_move_to(hdc, 10, sz.height/2);
cairo_set_font_size(hdc, 30);
cairo_show_text(hdc, "你好, 中国!");
cairo_stroke(hdc);
cairo_set_source_rgb(hdc, 0 , 0, 0);
cairo_move_to(hdc, 10, sz.height/2+30);
cairo_set_font_size(hdc, 18);
cairo_show_text(hdc, "--第三界主");
cairo_stroke(hdc);
cairo_destroy(hdc);
wlRequestPaintDone(hSurface);
wlEndPaint(hSurface, &ps);
}
void PaintDone(HSURFACE hSurface)
{
printf("PaintDone\n");
//wlRequestPaintDone(hSurface);
}
void PointerProc(HSURFACE hSurface, uint32_t button, uint32_t state, uint32_t serial)
{
LPSURFACEPRIVATE lpSurfacePrivate = wlGetSurfacePrivate(hSurface);
/* 鼠标左键按下了,移动窗口 */
if (BTN_LEFT == button && state == WL_POINTER_BUTTON_STATE_PRESSED)
{
HSHELLSURFACE hShellSurface = lpSurfacePrivate->hShellSurface;
wl_shell_surface_move(hShellSurface, wlGetRegistry()->s_seat, serial);
return;
}
}
int main(int argc, char **argv)
{
wlInit();
int width = 400, height = 300;
HSURFACE surface = wlCreateSurface("wayland-hello", width, height);
wlSetPaintProc(surface, PaintProc);
wlSetPaintDone(surface, PaintDone);
wlSetPointerProc(surface, PointerProc);
wlShowSurface(surface);
int ret = 0;
while (ret != -1)
{
ret = wlDispatch();
}
return 0;
}