mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
Merge branch 'wlcore'
This commit is contained in:
commit
8920b5d607
26 changed files with 322 additions and 46 deletions
81
examples/CMakeLists.txt
Normal file
81
examples/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
include_directories(
|
||||
${DRM_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${XKBCOMMON_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_executable(simple
|
||||
simple.c
|
||||
shared.c
|
||||
)
|
||||
|
||||
target_link_libraries(simple
|
||||
wlr-backend
|
||||
wlr-session
|
||||
${XKBCOMMON_LIBRARIES}
|
||||
)
|
||||
|
||||
add_executable(rotation
|
||||
rotation.c
|
||||
shared.c
|
||||
cat.c
|
||||
)
|
||||
|
||||
target_link_libraries(rotation
|
||||
wlr-backend
|
||||
wlr-session
|
||||
wlr-render
|
||||
${XKBCOMMON_LIBRARIES}
|
||||
)
|
||||
|
||||
add_executable(pointer
|
||||
pointer.c
|
||||
shared.c
|
||||
cat.c
|
||||
)
|
||||
|
||||
target_link_libraries(pointer
|
||||
wlr-backend
|
||||
wlr-session
|
||||
wlr-render
|
||||
${XKBCOMMON_LIBRARIES}
|
||||
)
|
||||
|
||||
add_executable(touch
|
||||
touch.c
|
||||
shared.c
|
||||
cat.c
|
||||
)
|
||||
|
||||
target_link_libraries(touch
|
||||
wlr-backend
|
||||
wlr-session
|
||||
wlr-render
|
||||
${XKBCOMMON_LIBRARIES}
|
||||
)
|
||||
|
||||
add_executable(tablet
|
||||
tablet.c
|
||||
shared.c
|
||||
)
|
||||
|
||||
target_link_libraries(tablet
|
||||
wlr-backend
|
||||
wlr-session
|
||||
wlr-render
|
||||
${XKBCOMMON_LIBRARIES}
|
||||
)
|
||||
|
||||
add_executable(compositor
|
||||
compositor/main.c
|
||||
compositor/wl_compositor.c
|
||||
compositor/wl_shell.c
|
||||
shared.c
|
||||
)
|
||||
|
||||
target_link_libraries(compositor
|
||||
wlr-backend
|
||||
wlr-session
|
||||
wlr-render
|
||||
${XKBCOMMON_LIBRARIES}
|
||||
)
|
||||
2644
examples/cat.c
Normal file
2644
examples/cat.c
Normal file
File diff suppressed because it is too large
Load diff
13
examples/cat.h
Normal file
13
examples/cat.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef _CAT_H
|
||||
#define _CAT_H
|
||||
|
||||
struct gimp_texture {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
|
||||
unsigned char pixel_data[128 * 128 * 3 + 1];
|
||||
};
|
||||
|
||||
extern const struct gimp_texture cat_tex;
|
||||
|
||||
#endif
|
||||
21
examples/compositor.h
Normal file
21
examples/compositor.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef _EXAMPLE_COMPOSITOR_H
|
||||
#define _EXAMPLE_COMPOSITOR_H
|
||||
#include <wayland-server.h>
|
||||
|
||||
struct wl_compositor_state {
|
||||
struct wl_global *wl_global;
|
||||
struct wl_list wl_resources;
|
||||
};
|
||||
|
||||
void wl_compositor_init(struct wl_display *display,
|
||||
struct wl_compositor_state *state);
|
||||
|
||||
struct wl_shell_state {
|
||||
struct wl_global *wl_global;
|
||||
struct wl_list wl_resources;
|
||||
};
|
||||
|
||||
void wl_shell_init(struct wl_display *display,
|
||||
struct wl_shell_state *state);
|
||||
|
||||
#endif
|
||||
49
examples/compositor/main.c
Normal file
49
examples/compositor/main.c
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/render.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "shared.h"
|
||||
#include "compositor.h"
|
||||
|
||||
struct sample_state {
|
||||
struct wlr_renderer *renderer;
|
||||
struct wl_compositor_state compositor;
|
||||
struct wl_shell_state shell;
|
||||
};
|
||||
|
||||
void handle_output_frame(struct output_state *output, struct timespec *ts) {
|
||||
struct compositor_state *state = output->compositor;
|
||||
struct sample_state *sample = state->data;
|
||||
struct wlr_output *wlr_output = output->output;
|
||||
|
||||
wlr_output_make_current(wlr_output);
|
||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||
// TODO: render surfaces
|
||||
wlr_renderer_end(sample->renderer);
|
||||
wlr_output_swap_buffers(wlr_output);
|
||||
}
|
||||
|
||||
int main() {
|
||||
struct sample_state state = { 0 };
|
||||
struct compositor_state compositor = { 0,
|
||||
.data = &state,
|
||||
.output_frame_cb = handle_output_frame,
|
||||
};
|
||||
compositor_init(&compositor);
|
||||
|
||||
state.renderer = wlr_gles2_renderer_init();
|
||||
wl_display_init_shm(compositor.display);
|
||||
wl_compositor_init(compositor.display, &state.compositor);
|
||||
wl_shell_init(compositor.display, &state.shell);
|
||||
|
||||
compositor_run(&compositor);
|
||||
}
|
||||
55
examples/compositor/wl_compositor.c
Normal file
55
examples/compositor/wl_compositor.c
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#include <assert.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "compositor.h"
|
||||
|
||||
static void wl_compositor_create_surface(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t id) {
|
||||
wlr_log(L_DEBUG, "TODO: implement create_surface");
|
||||
}
|
||||
|
||||
static void wl_compositor_create_region(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t id) {
|
||||
wlr_log(L_DEBUG, "TODO: implement create_region");
|
||||
}
|
||||
|
||||
struct wl_compositor_interface wl_compositor_impl = {
|
||||
.create_surface = wl_compositor_create_surface,
|
||||
.create_region = wl_compositor_create_region
|
||||
};
|
||||
|
||||
static void wl_compositor_destroy(struct wl_resource *resource) {
|
||||
struct wl_compositor_state *state = wl_resource_get_user_data(resource);
|
||||
struct wl_resource *_resource = NULL;
|
||||
wl_resource_for_each(_resource, &state->wl_resources) {
|
||||
if (_resource == resource) {
|
||||
struct wl_list *link = wl_resource_get_link(_resource);
|
||||
wl_list_remove(link);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_compositor_bind(struct wl_client *wl_client, void *_state,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wl_compositor_state *state = _state;
|
||||
assert(wl_client && state);
|
||||
if (version > 4) {
|
||||
wlr_log(L_ERROR, "Client requested unsupported wl_compositor version, disconnecting");
|
||||
wl_client_destroy(wl_client);
|
||||
return;
|
||||
}
|
||||
struct wl_resource *wl_resource = wl_resource_create(
|
||||
wl_client, &wl_compositor_interface, version, id);
|
||||
wl_resource_set_implementation(wl_resource, &wl_compositor_impl,
|
||||
state, wl_compositor_destroy);
|
||||
wl_list_insert(&state->wl_resources, wl_resource_get_link(wl_resource));
|
||||
}
|
||||
|
||||
void wl_compositor_init(struct wl_display *display,
|
||||
struct wl_compositor_state *state) {
|
||||
struct wl_global *wl_global = wl_global_create(display,
|
||||
&wl_compositor_interface, 4, state, wl_compositor_bind);
|
||||
state->wl_global = wl_global;
|
||||
wl_list_init(&state->wl_resources);
|
||||
}
|
||||
50
examples/compositor/wl_shell.c
Normal file
50
examples/compositor/wl_shell.c
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#include <assert.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "compositor.h"
|
||||
|
||||
void wl_shell_get_shell_surface(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t id,
|
||||
struct wl_resource *surface) {
|
||||
wlr_log(L_DEBUG, "TODO: implement get_shell_surface");
|
||||
}
|
||||
|
||||
static struct wl_shell_interface wl_shell_impl = {
|
||||
.get_shell_surface = wl_shell_get_shell_surface
|
||||
};
|
||||
|
||||
static void wl_shell_destroy(struct wl_resource *resource) {
|
||||
struct wl_shell_state *state = wl_resource_get_user_data(resource);
|
||||
struct wl_resource *_resource = NULL;
|
||||
wl_resource_for_each(_resource, &state->wl_resources) {
|
||||
if (_resource == resource) {
|
||||
struct wl_list *link = wl_resource_get_link(_resource);
|
||||
wl_list_remove(link);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_shell_bind(struct wl_client *wl_client, void *_state,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wl_shell_state *state = _state;
|
||||
assert(wl_client && state);
|
||||
if (version > 1) {
|
||||
wlr_log(L_ERROR, "Client requested unsupported wl_shell version, disconnecting");
|
||||
wl_client_destroy(wl_client);
|
||||
return;
|
||||
}
|
||||
struct wl_resource *wl_resource = wl_resource_create(
|
||||
wl_client, &wl_shell_interface, version, id);
|
||||
wl_resource_set_implementation(wl_resource, &wl_shell_impl,
|
||||
state, wl_shell_destroy);
|
||||
wl_list_insert(&state->wl_resources, wl_resource_get_link(wl_resource));
|
||||
}
|
||||
|
||||
void wl_shell_init(struct wl_display *display,
|
||||
struct wl_shell_state *state) {
|
||||
struct wl_global *wl_global = wl_global_create(display,
|
||||
&wl_shell_interface, 1, state, wl_shell_bind);
|
||||
state->wl_global = wl_global;
|
||||
wl_list_init(&state->wl_resources);
|
||||
}
|
||||
127
examples/pointer.c
Normal file
127
examples/pointer.c
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <wlr/render/matrix.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
#include <wlr/render.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "shared.h"
|
||||
#include "cat.h"
|
||||
|
||||
struct sample_state {
|
||||
double cur_x, cur_y;
|
||||
float default_color[4];
|
||||
float clear_color[4];
|
||||
};
|
||||
|
||||
static void handle_output_frame(struct output_state *output, struct timespec *ts) {
|
||||
struct compositor_state *state = output->compositor;
|
||||
struct sample_state *sample = state->data;
|
||||
struct wlr_output *wlr_output = output->output;
|
||||
|
||||
wlr_output_make_current(wlr_output);
|
||||
|
||||
glClearColor(sample->clear_color[0], sample->clear_color[1],
|
||||
sample->clear_color[2], sample->clear_color[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
wlr_output_swap_buffers(wlr_output);
|
||||
}
|
||||
|
||||
static void handle_pointer_motion(struct pointer_state *pstate,
|
||||
double d_x, double d_y) {
|
||||
struct sample_state *state = pstate->compositor->data;
|
||||
state->cur_x += d_x;
|
||||
state->cur_y += d_y;
|
||||
|
||||
struct output_state *output;
|
||||
wl_list_for_each(output, &pstate->compositor->outputs, link) {
|
||||
wlr_output_move_cursor(output->output, state->cur_x, state->cur_y);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_pointer_motion_absolute(struct pointer_state *pstate,
|
||||
double x, double y) {
|
||||
struct sample_state *state = pstate->compositor->data;
|
||||
state->cur_x = x;
|
||||
state->cur_y = y;
|
||||
|
||||
struct output_state *output;
|
||||
wl_list_for_each(output, &pstate->compositor->outputs, link) {
|
||||
wlr_output_move_cursor(output->output, state->cur_x, state->cur_y);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_pointer_button(struct pointer_state *pstate,
|
||||
uint32_t button, enum wlr_button_state state) {
|
||||
struct sample_state *sample = pstate->compositor->data;
|
||||
float (*color)[4];
|
||||
if (state == WLR_BUTTON_RELEASED) {
|
||||
color = &sample->default_color;
|
||||
} else {
|
||||
float red[4] = { 0.25f, 0.25f, 0.25f, 1 };
|
||||
red[button % 3] = 1;
|
||||
color = &red;
|
||||
}
|
||||
memcpy(&sample->clear_color, color, sizeof(*color));
|
||||
}
|
||||
|
||||
static void handle_pointer_axis(struct pointer_state *pstate,
|
||||
enum wlr_axis_source source,
|
||||
enum wlr_axis_orientation orientation,
|
||||
double delta) {
|
||||
struct sample_state *sample = pstate->compositor->data;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
sample->default_color[i] += delta > 0 ? -0.05f : 0.05f;
|
||||
if (sample->default_color[i] > 1.0f) {
|
||||
sample->default_color[i] = 1.0f;
|
||||
}
|
||||
if (sample->default_color[i] < 0.0f) {
|
||||
sample->default_color[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
memcpy(&sample->clear_color, &sample->default_color,
|
||||
sizeof(sample->clear_color));
|
||||
}
|
||||
|
||||
static void handle_output_add(struct output_state *ostate) {
|
||||
struct wlr_output *wlr_output = ostate->output;
|
||||
if (!wlr_output_set_cursor(wlr_output, cat_tex.pixel_data,
|
||||
cat_tex.width, cat_tex.width, cat_tex.height)) {
|
||||
wlr_log(L_DEBUG, "Failed to set hardware cursor");
|
||||
return;
|
||||
}
|
||||
if (!wlr_output_move_cursor(wlr_output, 0, 0)) {
|
||||
wlr_log(L_DEBUG, "Failed to move hardware cursor");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sample_state state = {
|
||||
.default_color = { 0.25f, 0.25f, 0.25f, 1 },
|
||||
.clear_color = { 0.25f, 0.25f, 0.25f, 1 }
|
||||
};
|
||||
struct compositor_state compositor = { 0 };
|
||||
compositor.data = &state;
|
||||
compositor.output_add_cb = handle_output_add;
|
||||
compositor.output_frame_cb = handle_output_frame;
|
||||
compositor.pointer_motion_cb = handle_pointer_motion;
|
||||
compositor.pointer_motion_absolute_cb = handle_pointer_motion_absolute;
|
||||
compositor.pointer_button_cb = handle_pointer_button;
|
||||
compositor.pointer_axis_cb = handle_pointer_axis;
|
||||
compositor_init(&compositor);
|
||||
|
||||
compositor_run(&compositor);
|
||||
}
|
||||
221
examples/rotation.c
Normal file
221
examples/rotation.c
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <wlr/render/matrix.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
#include <wlr/render.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <math.h>
|
||||
#include "shared.h"
|
||||
#include "cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct wl_list config;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_surface *cat_texture;
|
||||
};
|
||||
|
||||
struct output_data {
|
||||
float x_offs, y_offs;
|
||||
float x_vel, y_vel;
|
||||
};
|
||||
|
||||
struct output_config {
|
||||
char *name;
|
||||
enum wl_output_transform transform;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
static void handle_output_frame(struct output_state *output, struct timespec *ts) {
|
||||
struct compositor_state *state = output->compositor;
|
||||
struct sample_state *sample = state->data;
|
||||
struct output_data *odata = output->data;
|
||||
struct wlr_output *wlr_output = output->output;
|
||||
|
||||
int32_t width, height;
|
||||
wlr_output_effective_resolution(wlr_output, &width, &height);
|
||||
|
||||
wlr_output_make_current(wlr_output);
|
||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||
|
||||
float matrix[16];
|
||||
for (int y = -128 + (int)odata->y_offs; y < height; y += 128) {
|
||||
for (int x = -128 + (int)odata->x_offs; x < width; x += 128) {
|
||||
wlr_surface_get_matrix(sample->cat_texture, &matrix,
|
||||
&wlr_output->transform_matrix, x, y);
|
||||
wlr_render_with_matrix(sample->renderer,
|
||||
sample->cat_texture, &matrix);
|
||||
}
|
||||
}
|
||||
|
||||
wlr_renderer_end(sample->renderer);
|
||||
wlr_output_swap_buffers(wlr_output);
|
||||
|
||||
long ms = (ts->tv_sec - output->last_frame.tv_sec) * 1000 +
|
||||
(ts->tv_nsec - output->last_frame.tv_nsec) / 1000000;
|
||||
float seconds = ms / 1000.0f;
|
||||
|
||||
odata->x_offs += odata->x_vel * seconds;
|
||||
odata->y_offs += odata->y_vel * seconds;
|
||||
if (odata->x_offs > 128) odata->x_offs = 0;
|
||||
if (odata->y_offs > 128) odata->y_offs = 0;
|
||||
}
|
||||
|
||||
static void handle_output_add(struct output_state *output) {
|
||||
struct output_data *odata = calloc(1, sizeof(struct output_data));
|
||||
odata->x_offs = odata->y_offs = 0;
|
||||
odata->x_vel = odata->y_vel = 128;
|
||||
output->data = odata;
|
||||
struct sample_state *state = output->compositor->data;
|
||||
|
||||
struct output_config *conf;
|
||||
wl_list_for_each(conf, &state->config, link) {
|
||||
if (strcmp(conf->name, output->output->name) == 0) {
|
||||
wlr_output_transform(output->output, conf->transform);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_output_remove(struct output_state *output) {
|
||||
free(output->data);
|
||||
}
|
||||
|
||||
static void update_velocities(struct compositor_state *state,
|
||||
float x_diff, float y_diff) {
|
||||
struct output_state *output;
|
||||
wl_list_for_each(output, &state->outputs, link) {
|
||||
struct output_data *odata = output->data;
|
||||
odata->x_vel += x_diff;
|
||||
odata->y_vel += y_diff;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_keyboard_key(struct keyboard_state *kbstate,
|
||||
xkb_keysym_t sym, enum wlr_key_state key_state) {
|
||||
// NOTE: It may be better to simply refer to our key state during each frame
|
||||
// and make this change in pixels/sec^2
|
||||
// Also, key repeat
|
||||
if (key_state == WLR_KEY_PRESSED) {
|
||||
switch (sym) {
|
||||
case XKB_KEY_Left:
|
||||
update_velocities(kbstate->compositor, -16, 0);
|
||||
break;
|
||||
case XKB_KEY_Right:
|
||||
update_velocities(kbstate->compositor, 16, 0);
|
||||
break;
|
||||
case XKB_KEY_Up:
|
||||
update_velocities(kbstate->compositor, 0, -16);
|
||||
break;
|
||||
case XKB_KEY_Down:
|
||||
update_velocities(kbstate->compositor, 0, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(const char *name, int ret) {
|
||||
fprintf(stderr,
|
||||
"usage: %s [-d <name> [-r <rotation> | -f]]*\n"
|
||||
"\n"
|
||||
" -o <output> The name of the DRM display. e.g. DVI-I-1.\n"
|
||||
" -r <rotation> The rotation counter clockwise. Valid values are 90, 180, 270.\n"
|
||||
" -f Flip the output along the vertical axis.\n", name);
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
static void parse_args(int argc, char *argv[], struct wl_list *config) {
|
||||
struct output_config *oc = NULL;
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "o:r:fh")) != -1) {
|
||||
switch (c) {
|
||||
case 'o':
|
||||
oc = calloc(1, sizeof(*oc));
|
||||
oc->name = optarg;
|
||||
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
wl_list_insert(config, &oc->link);
|
||||
break;
|
||||
case 'r':
|
||||
if (!oc) {
|
||||
fprintf(stderr, "You must specify an output first\n");
|
||||
usage(argv[0], 1);
|
||||
}
|
||||
|
||||
if (oc->transform != WL_OUTPUT_TRANSFORM_NORMAL
|
||||
&& oc->transform != WL_OUTPUT_TRANSFORM_FLIPPED) {
|
||||
fprintf(stderr, "Rotation for %s already specified\n", oc->name);
|
||||
usage(argv[0], 1);
|
||||
}
|
||||
|
||||
if (strcmp(optarg, "90") == 0) {
|
||||
oc->transform += WL_OUTPUT_TRANSFORM_90;
|
||||
} else if (strcmp(optarg, "180") == 0) {
|
||||
oc->transform += WL_OUTPUT_TRANSFORM_180;
|
||||
} else if (strcmp(optarg, "270") == 0) {
|
||||
oc->transform += WL_OUTPUT_TRANSFORM_270;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid rotation '%s'\n", optarg);
|
||||
usage(argv[0], 1);
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (!oc) {
|
||||
fprintf(stderr, "You must specify an output first\n");
|
||||
usage(argv[0], 1);
|
||||
}
|
||||
|
||||
if (oc->transform >= WL_OUTPUT_TRANSFORM_FLIPPED) {
|
||||
fprintf(stderr, "Flip for %s already specified\n", oc->name);
|
||||
usage(argv[0], 1);
|
||||
}
|
||||
|
||||
oc->transform += WL_OUTPUT_TRANSFORM_FLIPPED;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
usage(argv[0], c != 'h');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sample_state state = { 0 };
|
||||
wl_list_init(&state.config);
|
||||
parse_args(argc, argv, &state.config);
|
||||
|
||||
struct compositor_state compositor = { 0 };
|
||||
compositor.data = &state;
|
||||
compositor.output_add_cb = handle_output_add;
|
||||
compositor.output_remove_cb = handle_output_remove;
|
||||
compositor.output_frame_cb = handle_output_frame;
|
||||
compositor.keyboard_key_cb = handle_keyboard_key;
|
||||
compositor_init(&compositor);
|
||||
|
||||
state.renderer = wlr_gles2_renderer_init();
|
||||
state.cat_texture = wlr_render_surface_init(state.renderer);
|
||||
wlr_surface_attach_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888,
|
||||
cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
|
||||
|
||||
compositor_run(&compositor);
|
||||
|
||||
wlr_surface_destroy(state.cat_texture);
|
||||
wlr_renderer_destroy(state.renderer);
|
||||
|
||||
struct output_config *ptr, *tmp;
|
||||
wl_list_for_each_safe(ptr, tmp, &state.config, link) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
493
examples/shared.c
Normal file
493
examples/shared.c
Normal file
|
|
@ -0,0 +1,493 @@
|
|||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "shared.h"
|
||||
|
||||
static void keyboard_led_update(struct keyboard_state *kbstate) {
|
||||
uint32_t leds = 0;
|
||||
for (uint32_t i = 0; i < WLR_LED_LAST; ++i) {
|
||||
if (xkb_state_led_index_is_active(kbstate->xkb_state, kbstate->leds[i])) {
|
||||
leds |= (1 << i);
|
||||
}
|
||||
}
|
||||
wlr_keyboard_led_update(kbstate->device->keyboard, leds);
|
||||
}
|
||||
|
||||
static void keyboard_key_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_keyboard_key *event = data;
|
||||
struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key);
|
||||
uint32_t keycode = event->keycode + 8;
|
||||
enum wlr_key_state key_state = event->state;
|
||||
const xkb_keysym_t *syms;
|
||||
int nsyms = xkb_state_key_get_syms(kbstate->xkb_state, keycode, &syms);
|
||||
for (int i = 0; i < nsyms; ++i) {
|
||||
xkb_keysym_t sym = syms[i];
|
||||
char name[64];
|
||||
int l = xkb_keysym_get_name(sym, name, sizeof(name));
|
||||
if (l != -1 && l != sizeof(name)) {
|
||||
wlr_log(L_DEBUG, "Key event: %s %s", name,
|
||||
key_state == WLR_KEY_PRESSED ? "pressed" : "released");
|
||||
}
|
||||
if (kbstate->compositor->keyboard_key_cb) {
|
||||
kbstate->compositor->keyboard_key_cb(kbstate, sym, key_state);
|
||||
}
|
||||
if (sym == XKB_KEY_Escape) {
|
||||
wl_display_terminate(kbstate->compositor->display);
|
||||
} else if (key_state == WLR_KEY_PRESSED && sym >= XKB_KEY_F1 && sym <= XKB_KEY_F12) {
|
||||
wlr_session_change_vt(kbstate->compositor->session, sym - XKB_KEY_F1 + 1);
|
||||
}
|
||||
}
|
||||
xkb_state_update_key(kbstate->xkb_state, keycode,
|
||||
event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
|
||||
keyboard_led_update(kbstate);
|
||||
}
|
||||
|
||||
static void keyboard_add(struct wlr_input_device *device, struct compositor_state *state) {
|
||||
struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1);
|
||||
kbstate->device = device;
|
||||
kbstate->compositor = state;
|
||||
wl_list_init(&kbstate->key.link);
|
||||
kbstate->key.notify = keyboard_key_notify;
|
||||
wl_signal_add(&device->keyboard->events.key, &kbstate->key);
|
||||
wl_list_insert(&state->keyboards, &kbstate->link);
|
||||
|
||||
struct xkb_rule_names rules;
|
||||
memset(&rules, 0, sizeof(rules));
|
||||
rules.rules = getenv("XKB_DEFAULT_RULES");
|
||||
rules.model = getenv("XKB_DEFAULT_MODEL");
|
||||
rules.layout = getenv("XKB_DEFAULT_LAYOUT");
|
||||
rules.variant = getenv("XKB_DEFAULT_VARIANT");
|
||||
rules.options = getenv("XKB_DEFAULT_OPTIONS");
|
||||
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!context) {
|
||||
wlr_log(L_ERROR, "Failed to create XKB context");
|
||||
exit(1);
|
||||
}
|
||||
kbstate->keymap = xkb_map_new_from_names(
|
||||
context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (!kbstate->keymap) {
|
||||
wlr_log(L_ERROR, "Failed to create XKB keymap");
|
||||
exit(1);
|
||||
}
|
||||
xkb_context_unref(context);
|
||||
kbstate->xkb_state = xkb_state_new(kbstate->keymap);
|
||||
if (!kbstate->xkb_state) {
|
||||
wlr_log(L_ERROR, "Failed to create XKB state");
|
||||
exit(1);
|
||||
}
|
||||
const char *led_names[3] = {
|
||||
XKB_LED_NAME_NUM,
|
||||
XKB_LED_NAME_CAPS,
|
||||
XKB_LED_NAME_SCROLL
|
||||
};
|
||||
for (uint32_t i = 0; i < 3; ++i) {
|
||||
kbstate->leds[i] = xkb_map_led_get_index(kbstate->keymap, led_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointer_motion_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_pointer_motion *event = data;
|
||||
struct pointer_state *pstate = wl_container_of(listener, pstate, motion);
|
||||
if (pstate->compositor->pointer_motion_cb) {
|
||||
pstate->compositor->pointer_motion_cb(pstate,
|
||||
event->delta_x, event->delta_y);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointer_motion_absolute_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_pointer_motion_absolute *event = data;
|
||||
struct pointer_state *pstate = wl_container_of(listener, pstate, motion_absolute);
|
||||
if (pstate->compositor->pointer_motion_absolute_cb) {
|
||||
pstate->compositor->pointer_motion_absolute_cb(pstate,
|
||||
event->x_mm, event->y_mm);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointer_button_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_pointer_button *event = data;
|
||||
struct pointer_state *pstate = wl_container_of(listener, pstate, button);
|
||||
if (pstate->compositor->pointer_button_cb) {
|
||||
pstate->compositor->pointer_button_cb(pstate,
|
||||
event->button, event->state);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointer_axis_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_pointer_axis *event = data;
|
||||
struct pointer_state *pstate = wl_container_of(listener, pstate, axis);
|
||||
if (pstate->compositor->pointer_axis_cb) {
|
||||
pstate->compositor->pointer_axis_cb(pstate,
|
||||
event->source, event->orientation, event->delta);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointer_add(struct wlr_input_device *device, struct compositor_state *state) {
|
||||
struct pointer_state *pstate = calloc(sizeof(struct pointer_state), 1);
|
||||
pstate->device = device;
|
||||
pstate->compositor = state;
|
||||
wl_list_init(&pstate->motion.link);
|
||||
wl_list_init(&pstate->motion_absolute.link);
|
||||
wl_list_init(&pstate->button.link);
|
||||
wl_list_init(&pstate->axis.link);
|
||||
pstate->motion.notify = pointer_motion_notify;
|
||||
pstate->motion_absolute.notify = pointer_motion_absolute_notify;
|
||||
pstate->button.notify = pointer_button_notify;
|
||||
pstate->axis.notify = pointer_axis_notify;
|
||||
wl_signal_add(&device->pointer->events.motion, &pstate->motion);
|
||||
wl_signal_add(&device->pointer->events.motion_absolute, &pstate->motion_absolute);
|
||||
wl_signal_add(&device->pointer->events.button, &pstate->button);
|
||||
wl_signal_add(&device->pointer->events.axis, &pstate->axis);
|
||||
wl_list_insert(&state->pointers, &pstate->link);
|
||||
}
|
||||
|
||||
static void touch_down_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_touch_down *event = data;
|
||||
struct touch_state *tstate = wl_container_of(listener, tstate, down);
|
||||
if (tstate->compositor->touch_down_cb) {
|
||||
tstate->compositor->touch_down_cb(tstate, event->slot,
|
||||
event->x_mm, event->y_mm, event->width_mm, event->height_mm);
|
||||
}
|
||||
}
|
||||
|
||||
static void touch_motion_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_touch_motion *event = data;
|
||||
struct touch_state *tstate = wl_container_of(listener, tstate, motion);
|
||||
if (tstate->compositor->touch_motion_cb) {
|
||||
tstate->compositor->touch_motion_cb(tstate, event->slot,
|
||||
event->x_mm, event->y_mm, event->width_mm, event->height_mm);
|
||||
}
|
||||
}
|
||||
|
||||
static void touch_up_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_touch_up *event = data;
|
||||
struct touch_state *tstate = wl_container_of(listener, tstate, up);
|
||||
if (tstate->compositor->touch_up_cb) {
|
||||
tstate->compositor->touch_up_cb(tstate, event->slot);
|
||||
}
|
||||
}
|
||||
|
||||
static void touch_cancel_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_touch_cancel *event = data;
|
||||
struct touch_state *tstate = wl_container_of(listener, tstate, cancel);
|
||||
if (tstate->compositor->touch_cancel_cb) {
|
||||
tstate->compositor->touch_cancel_cb(tstate, event->slot);
|
||||
}
|
||||
}
|
||||
|
||||
static void touch_add(struct wlr_input_device *device, struct compositor_state *state) {
|
||||
struct touch_state *tstate = calloc(sizeof(struct touch_state), 1);
|
||||
tstate->device = device;
|
||||
tstate->compositor = state;
|
||||
wl_list_init(&tstate->down.link);
|
||||
wl_list_init(&tstate->motion.link);
|
||||
wl_list_init(&tstate->up.link);
|
||||
wl_list_init(&tstate->cancel.link);
|
||||
tstate->down.notify = touch_down_notify;
|
||||
tstate->motion.notify = touch_motion_notify;
|
||||
tstate->up.notify = touch_up_notify;
|
||||
tstate->cancel.notify = touch_cancel_notify;
|
||||
wl_signal_add(&device->touch->events.down, &tstate->down);
|
||||
wl_signal_add(&device->touch->events.motion, &tstate->motion);
|
||||
wl_signal_add(&device->touch->events.up, &tstate->up);
|
||||
wl_signal_add(&device->touch->events.cancel, &tstate->cancel);
|
||||
wl_list_insert(&state->touch, &tstate->link);
|
||||
}
|
||||
|
||||
static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_tablet_tool_axis *event = data;
|
||||
struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis);
|
||||
if (tstate->compositor->tool_axis_cb) {
|
||||
tstate->compositor->tool_axis_cb(tstate, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void tablet_tool_proximity_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_tablet_tool_proximity *event = data;
|
||||
struct tablet_tool_state *tstate = wl_container_of(listener, tstate, proximity);
|
||||
if (tstate->compositor->tool_proximity_cb) {
|
||||
tstate->compositor->tool_proximity_cb(tstate, event->state);
|
||||
}
|
||||
}
|
||||
|
||||
static void tablet_tool_button_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_tablet_tool_button *event = data;
|
||||
struct tablet_tool_state *tstate = wl_container_of(listener, tstate, button);
|
||||
if (tstate->compositor->tool_button_cb) {
|
||||
tstate->compositor->tool_button_cb(tstate, event->button, event->state);
|
||||
}
|
||||
}
|
||||
|
||||
static void tablet_tool_add(struct wlr_input_device *device,
|
||||
struct compositor_state *state) {
|
||||
struct tablet_tool_state *tstate = calloc(sizeof(struct tablet_tool_state), 1);
|
||||
tstate->device = device;
|
||||
tstate->compositor = state;
|
||||
wl_list_init(&tstate->axis.link);
|
||||
wl_list_init(&tstate->proximity.link);
|
||||
wl_list_init(&tstate->tip.link);
|
||||
wl_list_init(&tstate->button.link);
|
||||
tstate->axis.notify = tablet_tool_axis_notify;
|
||||
tstate->proximity.notify = tablet_tool_proximity_notify;
|
||||
//tstate->tip.notify = tablet_tool_tip_notify;
|
||||
tstate->button.notify = tablet_tool_button_notify;
|
||||
wl_signal_add(&device->tablet_tool->events.axis, &tstate->axis);
|
||||
wl_signal_add(&device->tablet_tool->events.proximity, &tstate->proximity);
|
||||
//wl_signal_add(&device->tablet_tool->events.tip, &tstate->tip);
|
||||
wl_signal_add(&device->tablet_tool->events.button, &tstate->button);
|
||||
wl_list_insert(&state->tablet_tools, &tstate->link);
|
||||
}
|
||||
|
||||
static void tablet_pad_button_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_event_tablet_pad_button *event = data;
|
||||
struct tablet_pad_state *pstate = wl_container_of(listener, pstate, button);
|
||||
if (pstate->compositor->pad_button_cb) {
|
||||
pstate->compositor->pad_button_cb(pstate, event->button, event->state);
|
||||
}
|
||||
}
|
||||
|
||||
static void tablet_pad_add(struct wlr_input_device *device,
|
||||
struct compositor_state *state) {
|
||||
struct tablet_pad_state *pstate = calloc(sizeof(struct tablet_pad_state), 1);
|
||||
pstate->device = device;
|
||||
pstate->compositor = state;
|
||||
wl_list_init(&pstate->button.link);
|
||||
pstate->button.notify = tablet_pad_button_notify;
|
||||
wl_signal_add(&device->tablet_pad->events.button, &pstate->button);
|
||||
wl_list_insert(&state->tablet_pads, &pstate->link);
|
||||
}
|
||||
|
||||
static void input_add_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_input_device *device = data;
|
||||
struct compositor_state *state = wl_container_of(listener, state, input_add);
|
||||
switch (device->type) {
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
keyboard_add(device, state);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
pointer_add(device, state);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
touch_add(device, state);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
||||
tablet_tool_add(device, state);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_PAD:
|
||||
tablet_pad_add(device, state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void keyboard_remove(struct wlr_input_device *device, struct compositor_state *state) {
|
||||
struct keyboard_state *kbstate = NULL, *_kbstate;
|
||||
wl_list_for_each(_kbstate, &state->keyboards, link) {
|
||||
if (_kbstate->device == device) {
|
||||
kbstate = _kbstate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!kbstate) {
|
||||
return;
|
||||
}
|
||||
wl_list_remove(&kbstate->link);
|
||||
wl_list_remove(&kbstate->key.link);
|
||||
}
|
||||
|
||||
static void pointer_remove(struct wlr_input_device *device, struct compositor_state *state) {
|
||||
struct pointer_state *pstate = NULL, *_pstate;
|
||||
wl_list_for_each(_pstate, &state->pointers, link) {
|
||||
if (_pstate->device == device) {
|
||||
pstate = _pstate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pstate) {
|
||||
return;
|
||||
}
|
||||
wl_list_remove(&pstate->link);
|
||||
wl_list_remove(&pstate->motion.link);
|
||||
wl_list_remove(&pstate->motion_absolute.link);
|
||||
wl_list_remove(&pstate->button.link);
|
||||
wl_list_remove(&pstate->axis.link);
|
||||
}
|
||||
|
||||
static void touch_remove(struct wlr_input_device *device, struct compositor_state *state) {
|
||||
struct touch_state *tstate = NULL, *_tstate;
|
||||
wl_list_for_each(_tstate, &state->touch, link) {
|
||||
if (_tstate->device == device) {
|
||||
tstate = _tstate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!tstate) {
|
||||
return;
|
||||
}
|
||||
wl_list_remove(&tstate->link);
|
||||
wl_list_remove(&tstate->down.link);
|
||||
wl_list_remove(&tstate->motion.link);
|
||||
wl_list_remove(&tstate->up.link);
|
||||
wl_list_remove(&tstate->cancel.link);
|
||||
}
|
||||
|
||||
static void tablet_tool_remove(struct wlr_input_device *device, struct compositor_state *state) {
|
||||
struct tablet_tool_state *tstate = NULL, *_tstate;
|
||||
wl_list_for_each(_tstate, &state->tablet_tools, link) {
|
||||
if (_tstate->device == device) {
|
||||
tstate = _tstate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!tstate) {
|
||||
return;
|
||||
}
|
||||
wl_list_remove(&tstate->link);
|
||||
wl_list_remove(&tstate->axis.link);
|
||||
wl_list_remove(&tstate->proximity.link);
|
||||
//wl_list_remove(&tstate->tip.link);
|
||||
wl_list_remove(&tstate->button.link);
|
||||
}
|
||||
|
||||
static void input_remove_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_input_device *device = data;
|
||||
struct compositor_state *state = wl_container_of(listener, state, input_add);
|
||||
switch (device->type) {
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
keyboard_remove(device, state);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
pointer_remove(device, state);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
touch_remove(device, state);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
||||
tablet_tool_remove(device, state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void output_frame_notify(struct wl_listener *listener, void *data) {
|
||||
struct output_state *output = wl_container_of(listener, output, frame);
|
||||
struct compositor_state *compositor = output->compositor;
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (compositor->output_frame_cb) {
|
||||
compositor->output_frame_cb(output, &now);
|
||||
}
|
||||
|
||||
output->last_frame = now;
|
||||
compositor->last_frame = now;
|
||||
}
|
||||
|
||||
static void output_add_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct compositor_state *state = wl_container_of(listener, state, output_add);
|
||||
wlr_log(L_DEBUG, "Output '%s' added", output->name);
|
||||
wlr_log(L_DEBUG, "%s %s %"PRId32"mm x %"PRId32"mm", output->make, output->model,
|
||||
output->phys_width, output->phys_height);
|
||||
if (output->modes->length > 0) {
|
||||
wlr_output_set_mode(output, output->modes->items[0]);
|
||||
}
|
||||
struct output_state *ostate = calloc(1, sizeof(struct output_state));
|
||||
clock_gettime(CLOCK_MONOTONIC, &ostate->last_frame);
|
||||
ostate->output = output;
|
||||
ostate->compositor = state;
|
||||
ostate->frame.notify = output_frame_notify;
|
||||
wl_list_init(&ostate->frame.link);
|
||||
wl_signal_add(&output->events.frame, &ostate->frame);
|
||||
wl_list_insert(&state->outputs, &ostate->link);
|
||||
if (state->output_add_cb) {
|
||||
state->output_add_cb(ostate);
|
||||
}
|
||||
}
|
||||
|
||||
static void output_remove_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct compositor_state *state = wl_container_of(listener, state, output_remove);
|
||||
struct output_state *ostate = NULL, *_ostate;
|
||||
wl_list_for_each(_ostate, &state->outputs, link) {
|
||||
if (_ostate->output == output) {
|
||||
ostate = _ostate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ostate) {
|
||||
return; // We are unfamiliar with this output
|
||||
}
|
||||
if (state->output_remove_cb) {
|
||||
state->output_remove_cb(ostate);
|
||||
}
|
||||
wl_list_remove(&ostate->link);
|
||||
wl_list_remove(&ostate->frame.link);
|
||||
}
|
||||
|
||||
void compositor_init(struct compositor_state *state) {
|
||||
state->display = wl_display_create();
|
||||
state->event_loop = wl_display_get_event_loop(state->display);
|
||||
state->session = wlr_session_start(state->display);
|
||||
if (!state->session
|
||||
|| !state->display
|
||||
|| !state->event_loop) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
wl_list_init(&state->keyboards);
|
||||
wl_list_init(&state->pointers);
|
||||
wl_list_init(&state->touch);
|
||||
wl_list_init(&state->tablet_tools);
|
||||
wl_list_init(&state->tablet_pads);
|
||||
wl_list_init(&state->input_add.link);
|
||||
state->input_add.notify = input_add_notify;
|
||||
wl_list_init(&state->input_remove.link);
|
||||
state->input_remove.notify = input_remove_notify;
|
||||
|
||||
wl_list_init(&state->outputs);
|
||||
wl_list_init(&state->output_add.link);
|
||||
state->output_add.notify = output_add_notify;
|
||||
wl_list_init(&state->output_remove.link);
|
||||
state->output_remove.notify = output_remove_notify;
|
||||
|
||||
struct wlr_backend *wlr = wlr_backend_autocreate(
|
||||
state->display, state->session);
|
||||
if (!wlr) {
|
||||
exit(1);
|
||||
}
|
||||
wl_signal_add(&wlr->events.input_add, &state->input_add);
|
||||
wl_signal_add(&wlr->events.input_remove, &state->input_remove);
|
||||
wl_signal_add(&wlr->events.output_add, &state->output_add);
|
||||
wl_signal_add(&wlr->events.output_remove, &state->output_remove);
|
||||
state->backend = wlr;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &state->last_frame);
|
||||
|
||||
const char *socket = wl_display_add_socket_auto(state->display);
|
||||
wlr_log(L_INFO, "Running compositor on wayland display '%s'", socket);
|
||||
setenv("_WAYLAND_DISPLAY", socket, true);
|
||||
if (!wlr_backend_init(state->backend)) {
|
||||
wlr_log(L_ERROR, "Failed to initialize backend");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void compositor_run(struct compositor_state *state) {
|
||||
wl_display_run(state->display);
|
||||
wlr_backend_destroy(state->backend);
|
||||
wlr_session_finish(state->session);
|
||||
wl_display_destroy(state->display);
|
||||
}
|
||||
135
examples/shared.h
Normal file
135
examples/shared.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#ifndef _EXAMPLE_SHARED_H
|
||||
#define _EXAMPLE_SHARED_H
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
|
||||
struct output_state {
|
||||
struct compositor_state *compositor;
|
||||
struct wlr_output *output;
|
||||
struct wl_listener frame;
|
||||
struct timespec last_frame;
|
||||
struct wl_list link;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct keyboard_state {
|
||||
struct compositor_state *compositor;
|
||||
struct wlr_input_device *device;
|
||||
struct wl_listener key;
|
||||
struct wl_list link;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *xkb_state;
|
||||
xkb_led_index_t leds[WLR_LED_LAST];
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct pointer_state {
|
||||
struct compositor_state *compositor;
|
||||
struct wlr_input_device *device;
|
||||
struct wl_listener motion;
|
||||
struct wl_listener motion_absolute;
|
||||
struct wl_listener button;
|
||||
struct wl_listener axis;
|
||||
struct wl_list link;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct touch_state {
|
||||
struct compositor_state *compositor;
|
||||
struct wlr_input_device *device;
|
||||
struct wl_listener down;
|
||||
struct wl_listener up;
|
||||
struct wl_listener motion;
|
||||
struct wl_listener cancel;
|
||||
struct wl_list link;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct tablet_tool_state {
|
||||
struct compositor_state *compositor;
|
||||
struct wlr_input_device *device;
|
||||
struct wl_listener axis;
|
||||
struct wl_listener proximity;
|
||||
struct wl_listener tip;
|
||||
struct wl_listener button;
|
||||
struct wl_list link;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct tablet_pad_state {
|
||||
struct compositor_state *compositor;
|
||||
struct wlr_input_device *device;
|
||||
struct wl_listener button;
|
||||
struct wl_list link;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct compositor_state {
|
||||
void (*output_add_cb)(struct output_state *s);
|
||||
void (*keyboard_add_cb)(struct keyboard_state *s);
|
||||
void (*output_frame_cb)(struct output_state *s, struct timespec *ts);
|
||||
void (*output_remove_cb)(struct output_state *s);
|
||||
void (*keyboard_remove_cb)(struct keyboard_state *s);
|
||||
void (*keyboard_key_cb)(struct keyboard_state *s, xkb_keysym_t sym,
|
||||
enum wlr_key_state key_state);
|
||||
void (*pointer_motion_cb)(struct pointer_state *s,
|
||||
double d_x, double d_y);
|
||||
void (*pointer_motion_absolute_cb)(struct pointer_state *s,
|
||||
double x, double y);
|
||||
void (*pointer_button_cb)(struct pointer_state *s,
|
||||
uint32_t button, enum wlr_button_state state);
|
||||
void (*pointer_axis_cb)(struct pointer_state *s,
|
||||
enum wlr_axis_source source,
|
||||
enum wlr_axis_orientation orientation,
|
||||
double delta);
|
||||
void (*touch_down_cb)(struct touch_state *s, int32_t slot,
|
||||
double x, double y, double width, double height);
|
||||
void (*touch_motion_cb)(struct touch_state *s, int32_t slot,
|
||||
double x, double y, double width, double height);
|
||||
void (*touch_up_cb)(struct touch_state *s, int32_t slot);
|
||||
void (*touch_cancel_cb)(struct touch_state *s, int32_t slot);
|
||||
void (*tool_axis_cb)(struct tablet_tool_state *s,
|
||||
struct wlr_event_tablet_tool_axis *event);
|
||||
void (*tool_proximity_cb)(struct tablet_tool_state *s,
|
||||
enum wlr_tablet_tool_proximity_state proximity);
|
||||
void (*tool_tip_cb)(struct tablet_tool_state *s,
|
||||
enum wlr_tablet_tool_tip_state state);
|
||||
void (*tool_button_cb)(struct tablet_tool_state *s,
|
||||
uint32_t button, enum wlr_button_state state);
|
||||
void (*pad_button_cb)(struct tablet_pad_state *s,
|
||||
uint32_t button, enum wlr_button_state state);
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_event_loop *event_loop;
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_session *session;
|
||||
|
||||
struct wl_list keyboards;
|
||||
struct wl_list pointers;
|
||||
struct wl_list touch;
|
||||
struct wl_list tablet_tools;
|
||||
struct wl_list tablet_pads;
|
||||
struct wl_listener input_add;
|
||||
struct wl_listener input_remove;
|
||||
|
||||
struct timespec last_frame;
|
||||
struct wl_listener output_add;
|
||||
struct wl_listener output_remove;
|
||||
struct wl_list outputs;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
void compositor_init(struct compositor_state *state);
|
||||
void compositor_run(struct compositor_state *state);
|
||||
|
||||
#endif
|
||||
56
examples/simple.c
Normal file
56
examples/simple.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <wayland-server.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "shared.h"
|
||||
|
||||
struct sample_state {
|
||||
float color[3];
|
||||
int dec;
|
||||
};
|
||||
|
||||
void handle_output_frame(struct output_state *output, struct timespec *ts) {
|
||||
struct compositor_state *state = output->compositor;
|
||||
struct sample_state *sample = state->data;
|
||||
|
||||
long ms = (ts->tv_sec - state->last_frame.tv_sec) * 1000 +
|
||||
(ts->tv_nsec - state->last_frame.tv_nsec) / 1000000;
|
||||
int inc = (sample->dec + 1) % 3;
|
||||
|
||||
sample->color[inc] += ms / 2000.0f;
|
||||
sample->color[sample->dec] -= ms / 2000.0f;
|
||||
|
||||
if (sample->color[sample->dec] < 0.0f) {
|
||||
sample->color[inc] = 1.0f;
|
||||
sample->color[sample->dec] = 0.0f;
|
||||
sample->dec = inc;
|
||||
}
|
||||
|
||||
wlr_output_make_current(output->output);
|
||||
|
||||
glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
wlr_output_swap_buffers(output->output);
|
||||
}
|
||||
|
||||
int main() {
|
||||
struct sample_state state = {
|
||||
.color = { 1.0, 0.0, 0.0 },
|
||||
.dec = 0,
|
||||
};
|
||||
struct compositor_state compositor = { 0,
|
||||
.data = &state,
|
||||
.output_frame_cb = handle_output_frame,
|
||||
};
|
||||
compositor_init(&compositor);
|
||||
compositor_run(&compositor);
|
||||
}
|
||||
160
examples/tablet.c
Normal file
160
examples/tablet.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <wlr/render/matrix.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
#include <wlr/render.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
#include <wlr/types/wlr_tablet_pad.h>
|
||||
#include <math.h>
|
||||
#include "shared.h"
|
||||
#include "cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct wlr_renderer *renderer;
|
||||
bool proximity, tap, button;
|
||||
double distance;
|
||||
double pressure;
|
||||
double x_mm, y_mm;
|
||||
double width_mm, height_mm;
|
||||
struct wl_list link;
|
||||
float tool_color[4];
|
||||
float pad_color[4];
|
||||
};
|
||||
|
||||
static void handle_output_frame(struct output_state *output, struct timespec *ts) {
|
||||
struct compositor_state *state = output->compositor;
|
||||
struct sample_state *sample = state->data;
|
||||
struct wlr_output *wlr_output = output->output;
|
||||
|
||||
int32_t width, height;
|
||||
wlr_output_effective_resolution(wlr_output, &width, &height);
|
||||
|
||||
wlr_output_make_current(wlr_output);
|
||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||
|
||||
float matrix[16], view[16];
|
||||
float distance = 0.8f * (1 - sample->distance);
|
||||
float tool_color[4] = { distance, distance, distance, 1 };
|
||||
for (size_t i = 0; sample->button && i < 4; ++i) {
|
||||
tool_color[i] = sample->tool_color[i];
|
||||
}
|
||||
float scale = 4;
|
||||
|
||||
float pad_width = sample->width_mm * scale;
|
||||
float pad_height = sample->height_mm * scale;
|
||||
float left = width / 2.0f - pad_width / 2.0f;
|
||||
float top = height / 2.0f - pad_height / 2.0f;
|
||||
wlr_matrix_translate(&matrix, left, top, 0);
|
||||
wlr_matrix_scale(&view, pad_width, pad_height, 1);
|
||||
wlr_matrix_mul(&matrix, &view, &view);
|
||||
wlr_matrix_mul(&wlr_output->transform_matrix, &view, &matrix);
|
||||
wlr_render_colored_quad(sample->renderer, &sample->pad_color, &matrix);
|
||||
|
||||
if (sample->proximity) {
|
||||
wlr_matrix_translate(&matrix,
|
||||
sample->x_mm * scale - 8 * (sample->pressure + 1) + left,
|
||||
sample->y_mm * scale - 8 * (sample->pressure + 1) + top, 0);
|
||||
wlr_matrix_scale(&view,
|
||||
16 * (sample->pressure + 1),
|
||||
16 * (sample->pressure + 1), 1);
|
||||
wlr_matrix_mul(&matrix, &view, &view);
|
||||
wlr_matrix_mul(&wlr_output->transform_matrix, &view, &matrix);
|
||||
wlr_render_colored_ellipse(sample->renderer, &tool_color, &matrix);
|
||||
}
|
||||
|
||||
wlr_renderer_end(sample->renderer);
|
||||
wlr_output_swap_buffers(wlr_output);
|
||||
}
|
||||
|
||||
static void handle_tool_axis(struct tablet_tool_state *tstate,
|
||||
struct wlr_event_tablet_tool_axis *event) {
|
||||
struct sample_state *sample = tstate->compositor->data;
|
||||
sample->width_mm = event->width_mm;
|
||||
sample->height_mm = event->height_mm;
|
||||
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) {
|
||||
sample->x_mm = event->x_mm;
|
||||
}
|
||||
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) {
|
||||
sample->y_mm = event->y_mm;
|
||||
}
|
||||
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)) {
|
||||
sample->distance = event->distance;
|
||||
}
|
||||
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)) {
|
||||
sample->pressure = event->pressure;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_tool_proximity(struct tablet_tool_state *tstate,
|
||||
enum wlr_tablet_tool_proximity_state state) {
|
||||
struct sample_state *sample = tstate->compositor->data;
|
||||
sample->proximity = state == WLR_TABLET_TOOL_PROXIMITY_IN;
|
||||
}
|
||||
|
||||
static void handle_tool_button(struct tablet_tool_state *tstate,
|
||||
uint32_t button, enum wlr_button_state state) {
|
||||
struct sample_state *sample = tstate->compositor->data;
|
||||
if (state == WLR_BUTTON_RELEASED) {
|
||||
sample->button = false;
|
||||
} else {
|
||||
sample->button = true;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (button % 3 == i) {
|
||||
sample->tool_color[i] = 0;
|
||||
} else {
|
||||
sample->tool_color[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_pad_button(struct tablet_pad_state *pstate,
|
||||
uint32_t button, enum wlr_button_state state) {
|
||||
struct sample_state *sample = pstate->compositor->data;
|
||||
float default_color[4] = { 0.75, 0.75, 0.75, 1.0 };
|
||||
if (state == WLR_BUTTON_RELEASED) {
|
||||
memcpy(sample->pad_color, default_color, sizeof(default_color));
|
||||
} else {
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (button % 3 == i) {
|
||||
sample->pad_color[i] = 0;
|
||||
} else {
|
||||
sample->pad_color[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sample_state state = {
|
||||
.tool_color = { 1, 1, 1, 1 },
|
||||
.pad_color = { 0.75, 0.75, 0.75, 1.0 }
|
||||
};
|
||||
struct compositor_state compositor = { 0,
|
||||
.data = &state,
|
||||
.output_frame_cb = handle_output_frame,
|
||||
.tool_axis_cb = handle_tool_axis,
|
||||
.tool_proximity_cb = handle_tool_proximity,
|
||||
.tool_button_cb = handle_tool_button,
|
||||
.pad_button_cb = handle_pad_button,
|
||||
};
|
||||
compositor_init(&compositor);
|
||||
|
||||
state.renderer = wlr_gles2_renderer_init();
|
||||
|
||||
compositor_run(&compositor);
|
||||
|
||||
wlr_renderer_destroy(state.renderer);
|
||||
}
|
||||
116
examples/touch.c
Normal file
116
examples/touch.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <wlr/render/matrix.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
#include <wlr/render.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/session.h>
|
||||
#include <wlr/util/list.h>
|
||||
#include "shared.h"
|
||||
#include "cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_surface *cat_texture;
|
||||
list_t *touch_points;
|
||||
};
|
||||
|
||||
struct touch_point {
|
||||
int32_t slot;
|
||||
double x, y;
|
||||
};
|
||||
|
||||
static void handle_output_frame(struct output_state *output, struct timespec *ts) {
|
||||
struct compositor_state *state = output->compositor;
|
||||
struct sample_state *sample = state->data;
|
||||
struct wlr_output *wlr_output = output->output;
|
||||
|
||||
int32_t width, height;
|
||||
wlr_output_effective_resolution(wlr_output, &width, &height);
|
||||
|
||||
wlr_output_make_current(wlr_output);
|
||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||
|
||||
float matrix[16];
|
||||
for (size_t i = 0; i < sample->touch_points->length; ++i) {
|
||||
struct touch_point *p = sample->touch_points->items[i];
|
||||
wlr_surface_get_matrix(sample->cat_texture, &matrix,
|
||||
&wlr_output->transform_matrix,
|
||||
(int)(p->x * width) - sample->cat_texture->width / 2,
|
||||
(int)(p->y * height) - sample->cat_texture->height / 2);
|
||||
wlr_render_with_matrix(sample->renderer,
|
||||
sample->cat_texture, &matrix);
|
||||
}
|
||||
|
||||
wlr_renderer_end(sample->renderer);
|
||||
wlr_output_swap_buffers(wlr_output);
|
||||
}
|
||||
|
||||
static void handle_touch_down(struct touch_state *tstate, int32_t slot,
|
||||
double x, double y, double width, double height) {
|
||||
struct sample_state *sample = tstate->compositor->data;
|
||||
struct touch_point *point = calloc(1, sizeof(struct touch_state));
|
||||
point->slot = slot;
|
||||
point->x = x / width;
|
||||
point->y = y / height;
|
||||
list_add(sample->touch_points, point);
|
||||
}
|
||||
|
||||
static void handle_touch_up(struct touch_state *tstate, int32_t slot) {
|
||||
struct sample_state *sample = tstate->compositor->data;
|
||||
for (size_t i = 0; i < sample->touch_points->length; ++i) {
|
||||
struct touch_point *point = sample->touch_points->items[i];
|
||||
if (point->slot == slot) {
|
||||
list_del(sample->touch_points, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_touch_motion(struct touch_state *tstate, int32_t slot,
|
||||
double x, double y, double width, double height) {
|
||||
struct sample_state *sample = tstate->compositor->data;
|
||||
for (size_t i = 0; i < sample->touch_points->length; ++i) {
|
||||
struct touch_point *point = sample->touch_points->items[i];
|
||||
if (point->slot == slot) {
|
||||
point->x = x / width;
|
||||
point->y = y / height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sample_state state = {
|
||||
.touch_points = list_create()
|
||||
};
|
||||
struct compositor_state compositor = { 0,
|
||||
.data = &state,
|
||||
.output_frame_cb = handle_output_frame,
|
||||
.touch_down_cb = handle_touch_down,
|
||||
.touch_up_cb = handle_touch_up,
|
||||
.touch_motion_cb = handle_touch_motion,
|
||||
};
|
||||
compositor_init(&compositor);
|
||||
|
||||
state.renderer = wlr_gles2_renderer_init();
|
||||
state.cat_texture = wlr_render_surface_init(state.renderer);
|
||||
wlr_surface_attach_pixels(state.cat_texture, GL_RGBA,
|
||||
cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
|
||||
|
||||
compositor_run(&compositor);
|
||||
|
||||
wlr_surface_destroy(state.cat_texture);
|
||||
wlr_renderer_destroy(state.renderer);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue